xref: /onnv-gate/usr/src/uts/sparc/io/pciex/pcieb_sparc.c (revision 10187:ad62e2dfbe0c)
1*10187SKrishna.Elango@Sun.COM /*
2*10187SKrishna.Elango@Sun.COM  * CDDL HEADER START
3*10187SKrishna.Elango@Sun.COM  *
4*10187SKrishna.Elango@Sun.COM  * The contents of this file are subject to the terms of the
5*10187SKrishna.Elango@Sun.COM  * Common Development and Distribution License (the "License").
6*10187SKrishna.Elango@Sun.COM  * You may not use this file except in compliance with the License.
7*10187SKrishna.Elango@Sun.COM  *
8*10187SKrishna.Elango@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10187SKrishna.Elango@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10187SKrishna.Elango@Sun.COM  * See the License for the specific language governing permissions
11*10187SKrishna.Elango@Sun.COM  * and limitations under the License.
12*10187SKrishna.Elango@Sun.COM  *
13*10187SKrishna.Elango@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10187SKrishna.Elango@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10187SKrishna.Elango@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10187SKrishna.Elango@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10187SKrishna.Elango@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10187SKrishna.Elango@Sun.COM  *
19*10187SKrishna.Elango@Sun.COM  * CDDL HEADER END
20*10187SKrishna.Elango@Sun.COM  */
21*10187SKrishna.Elango@Sun.COM /*
22*10187SKrishna.Elango@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*10187SKrishna.Elango@Sun.COM  * Use is subject to license terms.
24*10187SKrishna.Elango@Sun.COM  */
25*10187SKrishna.Elango@Sun.COM 
26*10187SKrishna.Elango@Sun.COM /* SPARC specific code used by the pcieb driver */
27*10187SKrishna.Elango@Sun.COM 
28*10187SKrishna.Elango@Sun.COM #include <sys/types.h>
29*10187SKrishna.Elango@Sun.COM #include <sys/ddi.h>
30*10187SKrishna.Elango@Sun.COM #include <sys/kmem.h>
31*10187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h>
32*10187SKrishna.Elango@Sun.COM #include <sys/sunddi.h>
33*10187SKrishna.Elango@Sun.COM #include <sys/sunndi.h>
34*10187SKrishna.Elango@Sun.COM #include <sys/pcie.h>
35*10187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h>
36*10187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h>
37*10187SKrishna.Elango@Sun.COM #include <io/pciex/pcieb.h>
38*10187SKrishna.Elango@Sun.COM #include "pcieb_plx.h"
39*10187SKrishna.Elango@Sun.COM 
40*10187SKrishna.Elango@Sun.COM /*LINTLIBRARY*/
41*10187SKrishna.Elango@Sun.COM 
42*10187SKrishna.Elango@Sun.COM /* PLX specific functions */
43*10187SKrishna.Elango@Sun.COM #ifdef	PX_PLX
44*10187SKrishna.Elango@Sun.COM static void plx_ro_disable(pcieb_devstate_t *pcieb);
45*10187SKrishna.Elango@Sun.COM #ifdef	PRINT_PLX_SEEPROM_CRC
46*10187SKrishna.Elango@Sun.COM static void pcieb_print_plx_seeprom_crc_data(pcieb_devstate_t *pcieb_p);
47*10187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */
48*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */
49*10187SKrishna.Elango@Sun.COM 
50*10187SKrishna.Elango@Sun.COM int
51*10187SKrishna.Elango@Sun.COM pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
52*10187SKrishna.Elango@Sun.COM     void *arg, void *result)
53*10187SKrishna.Elango@Sun.COM {
54*10187SKrishna.Elango@Sun.COM 	return (ddi_ctlops(dip, rdip, ctlop, arg, result));
55*10187SKrishna.Elango@Sun.COM }
56*10187SKrishna.Elango@Sun.COM 
57*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
58*10187SKrishna.Elango@Sun.COM void
59*10187SKrishna.Elango@Sun.COM pcieb_plat_attach_workaround(dev_info_t *dip)
60*10187SKrishna.Elango@Sun.COM {
61*10187SKrishna.Elango@Sun.COM }
62*10187SKrishna.Elango@Sun.COM 
63*10187SKrishna.Elango@Sun.COM int
64*10187SKrishna.Elango@Sun.COM pcieb_plat_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
65*10187SKrishna.Elango@Sun.COM     ddi_intr_handle_impl_t *hdlp, void *result)
66*10187SKrishna.Elango@Sun.COM {
67*10187SKrishna.Elango@Sun.COM 	dev_info_t	*cdip = rdip;
68*10187SKrishna.Elango@Sun.COM 	pci_regspec_t	*pci_rp;
69*10187SKrishna.Elango@Sun.COM 	int		reglen, len;
70*10187SKrishna.Elango@Sun.COM 	uint32_t	d, intr;
71*10187SKrishna.Elango@Sun.COM 
72*10187SKrishna.Elango@Sun.COM 	if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) ||
73*10187SKrishna.Elango@Sun.COM 	    (hdlp->ih_type != DDI_INTR_TYPE_FIXED))
74*10187SKrishna.Elango@Sun.COM 		goto done;
75*10187SKrishna.Elango@Sun.COM 
76*10187SKrishna.Elango@Sun.COM 	/*
77*10187SKrishna.Elango@Sun.COM 	 * If the interrupt-map property is defined at this
78*10187SKrishna.Elango@Sun.COM 	 * node, it will have performed the interrupt
79*10187SKrishna.Elango@Sun.COM 	 * translation as part of the property, so no
80*10187SKrishna.Elango@Sun.COM 	 * rotation needs to be done.
81*10187SKrishna.Elango@Sun.COM 	 */
82*10187SKrishna.Elango@Sun.COM 	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
83*10187SKrishna.Elango@Sun.COM 	    "interrupt-map", &len) == DDI_PROP_SUCCESS)
84*10187SKrishna.Elango@Sun.COM 		goto done;
85*10187SKrishna.Elango@Sun.COM 
86*10187SKrishna.Elango@Sun.COM 	cdip = pcie_get_my_childs_dip(dip, rdip);
87*10187SKrishna.Elango@Sun.COM 
88*10187SKrishna.Elango@Sun.COM 	/*
89*10187SKrishna.Elango@Sun.COM 	 * Use the devices reg property to determine its
90*10187SKrishna.Elango@Sun.COM 	 * PCI bus number and device number.
91*10187SKrishna.Elango@Sun.COM 	 */
92*10187SKrishna.Elango@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
93*10187SKrishna.Elango@Sun.COM 	    "reg", (caddr_t)&pci_rp, &reglen) != DDI_SUCCESS)
94*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
95*10187SKrishna.Elango@Sun.COM 
96*10187SKrishna.Elango@Sun.COM 	intr = hdlp->ih_vector;
97*10187SKrishna.Elango@Sun.COM 
98*10187SKrishna.Elango@Sun.COM 	/* spin the interrupt */
99*10187SKrishna.Elango@Sun.COM 	d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
100*10187SKrishna.Elango@Sun.COM 	if ((intr >= PCI_INTA) && (intr <= PCI_INTD))
101*10187SKrishna.Elango@Sun.COM 		hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1);
102*10187SKrishna.Elango@Sun.COM 	else
103*10187SKrishna.Elango@Sun.COM 		cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range",
104*10187SKrishna.Elango@Sun.COM 		    ddi_driver_name(rdip), ddi_get_instance(rdip),
105*10187SKrishna.Elango@Sun.COM 		    ddi_driver_name(dip), intr);
106*10187SKrishna.Elango@Sun.COM 
107*10187SKrishna.Elango@Sun.COM 	kmem_free(pci_rp, reglen);
108*10187SKrishna.Elango@Sun.COM 
109*10187SKrishna.Elango@Sun.COM done:
110*10187SKrishna.Elango@Sun.COM 	/* Pass up the request to our parent. */
111*10187SKrishna.Elango@Sun.COM 	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
112*10187SKrishna.Elango@Sun.COM }
113*10187SKrishna.Elango@Sun.COM 
114*10187SKrishna.Elango@Sun.COM int
115*10187SKrishna.Elango@Sun.COM pcieb_plat_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
116*10187SKrishna.Elango@Sun.COM {
117*10187SKrishna.Elango@Sun.COM 	uint16_t cap_ptr;
118*10187SKrishna.Elango@Sun.COM 	if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_HOTPLUG, &cap_ptr)) !=
119*10187SKrishna.Elango@Sun.COM 	    DDI_FAILURE) {
120*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
121*10187SKrishna.Elango@Sun.COM 	}
122*10187SKrishna.Elango@Sun.COM 
123*10187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
124*10187SKrishna.Elango@Sun.COM }
125*10187SKrishna.Elango@Sun.COM 
126*10187SKrishna.Elango@Sun.COM /*
127*10187SKrishna.Elango@Sun.COM  *  Disable PM on PLX. For PLX Transitioning one port on this switch to
128*10187SKrishna.Elango@Sun.COM  *  low power causes links on other ports on the same station to die.
129*10187SKrishna.Elango@Sun.COM  *  Due to PLX erratum #34, we can't allow the downstream device go to
130*10187SKrishna.Elango@Sun.COM  *  non-D0 state.
131*10187SKrishna.Elango@Sun.COM  */
132*10187SKrishna.Elango@Sun.COM boolean_t
133*10187SKrishna.Elango@Sun.COM pcieb_plat_pwr_disable(dev_info_t *dip)
134*10187SKrishna.Elango@Sun.COM {
135*10187SKrishna.Elango@Sun.COM 	uint16_t vendor_id = (PCIE_DIP2UPBUS(dip)->bus_dev_ven_id) & 0xFFFF;
136*10187SKrishna.Elango@Sun.COM 	return (IS_PLX_VENDORID(vendor_id) ? B_TRUE : B_FALSE);
137*10187SKrishna.Elango@Sun.COM }
138*10187SKrishna.Elango@Sun.COM 
139*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
140*10187SKrishna.Elango@Sun.COM boolean_t
141*10187SKrishna.Elango@Sun.COM pcieb_plat_msi_supported(dev_info_t *dip)
142*10187SKrishna.Elango@Sun.COM {
143*10187SKrishna.Elango@Sun.COM 	return (B_TRUE);
144*10187SKrishna.Elango@Sun.COM }
145*10187SKrishna.Elango@Sun.COM 
146*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
147*10187SKrishna.Elango@Sun.COM void
148*10187SKrishna.Elango@Sun.COM pcieb_plat_intr_attach(pcieb_devstate_t *pcieb)
149*10187SKrishna.Elango@Sun.COM {
150*10187SKrishna.Elango@Sun.COM }
151*10187SKrishna.Elango@Sun.COM 
152*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
153*10187SKrishna.Elango@Sun.COM int
154*10187SKrishna.Elango@Sun.COM pcieb_plat_ctlops(dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg)
155*10187SKrishna.Elango@Sun.COM {
156*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
157*10187SKrishna.Elango@Sun.COM }
158*10187SKrishna.Elango@Sun.COM 
159*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
160*10187SKrishna.Elango@Sun.COM void
161*10187SKrishna.Elango@Sun.COM pcieb_plat_ioctl_hotplug(dev_info_t *dip, int rv, int cmd)
162*10187SKrishna.Elango@Sun.COM {
163*10187SKrishna.Elango@Sun.COM }
164*10187SKrishna.Elango@Sun.COM 
165*10187SKrishna.Elango@Sun.COM void
166*10187SKrishna.Elango@Sun.COM pcieb_plat_initchild(dev_info_t *child)
167*10187SKrishna.Elango@Sun.COM {
168*10187SKrishna.Elango@Sun.COM 	intptr_t ppd = NULL;
169*10187SKrishna.Elango@Sun.COM 	/*
170*10187SKrishna.Elango@Sun.COM 	 * XXX set ppd to 1 to disable iommu BDF protection on SPARC.
171*10187SKrishna.Elango@Sun.COM 	 * It relies on unused parent private data for PCI devices.
172*10187SKrishna.Elango@Sun.COM 	 */
173*10187SKrishna.Elango@Sun.COM 	if (ddi_prop_exists(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
174*10187SKrishna.Elango@Sun.COM 	    "dvma-share"))
175*10187SKrishna.Elango@Sun.COM 		ppd = 1;
176*10187SKrishna.Elango@Sun.COM 
177*10187SKrishna.Elango@Sun.COM 	ddi_set_parent_data(child, (void *)ppd);
178*10187SKrishna.Elango@Sun.COM }
179*10187SKrishna.Elango@Sun.COM 
180*10187SKrishna.Elango@Sun.COM void
181*10187SKrishna.Elango@Sun.COM pcieb_plat_uninitchild(dev_info_t *child)
182*10187SKrishna.Elango@Sun.COM {
183*10187SKrishna.Elango@Sun.COM 	/*
184*10187SKrishna.Elango@Sun.COM 	 * XXX Clear parent private data used as a flag to disable
185*10187SKrishna.Elango@Sun.COM 	 * iommu BDF protection
186*10187SKrishna.Elango@Sun.COM 	 */
187*10187SKrishna.Elango@Sun.COM 	if ((intptr_t)ddi_get_parent_data(child) == 1)
188*10187SKrishna.Elango@Sun.COM 		ddi_set_parent_data(child, NULL);
189*10187SKrishna.Elango@Sun.COM }
190*10187SKrishna.Elango@Sun.COM 
191*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX
192*10187SKrishna.Elango@Sun.COM /*
193*10187SKrishna.Elango@Sun.COM  * These are PLX specific workarounds needed during attach.
194*10187SKrishna.Elango@Sun.COM  */
195*10187SKrishna.Elango@Sun.COM void
196*10187SKrishna.Elango@Sun.COM pcieb_attach_plx_workarounds(pcieb_devstate_t *pcieb)
197*10187SKrishna.Elango@Sun.COM {
198*10187SKrishna.Elango@Sun.COM 	dev_info_t	*dip = pcieb->pcieb_dip;
199*10187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
200*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t	config_handle = bus_p->bus_cfg_hdl;
201*10187SKrishna.Elango@Sun.COM 	uint_t		bus_num, primary, secondary;
202*10187SKrishna.Elango@Sun.COM 	uint8_t		dev_type = bus_p->bus_dev_type;
203*10187SKrishna.Elango@Sun.COM 	uint16_t	vendor_id = bus_p->bus_dev_ven_id & 0xFFFF;
204*10187SKrishna.Elango@Sun.COM 
205*10187SKrishna.Elango@Sun.COM 	if (!IS_PLX_VENDORID(vendor_id))
206*10187SKrishna.Elango@Sun.COM 		return;
207*10187SKrishna.Elango@Sun.COM 
208*10187SKrishna.Elango@Sun.COM 	/*
209*10187SKrishna.Elango@Sun.COM 	 * Due to a PLX HW bug we need to disable the receiver error CE on all
210*10187SKrishna.Elango@Sun.COM 	 * ports. To this end we create a property "pcie_ce_mask" with value
211*10187SKrishna.Elango@Sun.COM 	 * set to PCIE_AER_CE_RECEIVER_ERR. The pcie module will check for this
212*10187SKrishna.Elango@Sun.COM 	 * property before setting the AER CE mask.
213*10187SKrishna.Elango@Sun.COM 	 */
214*10187SKrishna.Elango@Sun.COM 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
215*10187SKrishna.Elango@Sun.COM 	    "pcie_ce_mask", PCIE_AER_CE_RECEIVER_ERR);
216*10187SKrishna.Elango@Sun.COM 
217*10187SKrishna.Elango@Sun.COM 	/*
218*10187SKrishna.Elango@Sun.COM 	 * There is a bug in the PLX 8114 bridge, such that an 8-bit
219*10187SKrishna.Elango@Sun.COM 	 * write to the secondary bus number register will corrupt an
220*10187SKrishna.Elango@Sun.COM 	 * internal shadow copy of the primary bus number.  Reading
221*10187SKrishna.Elango@Sun.COM 	 * out the registers and writing the same values back as
222*10187SKrishna.Elango@Sun.COM 	 * 16-bits resolves the problem.  This bug was reported by
223*10187SKrishna.Elango@Sun.COM 	 * PLX as errata #19.
224*10187SKrishna.Elango@Sun.COM 	 */
225*10187SKrishna.Elango@Sun.COM 	primary = pci_config_get8(config_handle, PCI_BCNF_PRIBUS);
226*10187SKrishna.Elango@Sun.COM 	secondary = pci_config_get8(config_handle, PCI_BCNF_SECBUS);
227*10187SKrishna.Elango@Sun.COM 	bus_num = (secondary << 8) | primary;
228*10187SKrishna.Elango@Sun.COM 	pci_config_put16(config_handle, PCI_BCNF_PRIBUS, bus_num);
229*10187SKrishna.Elango@Sun.COM 
230*10187SKrishna.Elango@Sun.COM 	/*
231*10187SKrishna.Elango@Sun.COM 	 * Workaround for a race condition between hotplug
232*10187SKrishna.Elango@Sun.COM 	 * initialization and actual MSI interrupt registration
233*10187SKrishna.Elango@Sun.COM 	 * for hotplug functionality. The hotplug initialization
234*10187SKrishna.Elango@Sun.COM 	 * generates an INTx interrupt for hotplug events and this
235*10187SKrishna.Elango@Sun.COM 	 * INTx interrupt may interfere with shared leaf drivers
236*10187SKrishna.Elango@Sun.COM 	 * using same INTx interrupt, which may eventually block
237*10187SKrishna.Elango@Sun.COM 	 * the leaf drivers.
238*10187SKrishna.Elango@Sun.COM 	 */
239*10187SKrishna.Elango@Sun.COM 	if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
240*10187SKrishna.Elango@Sun.COM 	    (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
241*10187SKrishna.Elango@Sun.COM 	    (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ||
242*10187SKrishna.Elango@Sun.COM 	    (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
243*10187SKrishna.Elango@Sun.COM 		pci_config_put16(config_handle, PCI_CONF_COMM,
244*10187SKrishna.Elango@Sun.COM 		    pci_config_get16(config_handle, PCI_CONF_COMM) |
245*10187SKrishna.Elango@Sun.COM 		    PCI_COMM_INTX_DISABLE);
246*10187SKrishna.Elango@Sun.COM 	}
247*10187SKrishna.Elango@Sun.COM 
248*10187SKrishna.Elango@Sun.COM 	/*
249*10187SKrishna.Elango@Sun.COM 	 * Disable PLX Special Relaxed Ordering
250*10187SKrishna.Elango@Sun.COM 	 */
251*10187SKrishna.Elango@Sun.COM 	plx_ro_disable(pcieb);
252*10187SKrishna.Elango@Sun.COM 
253*10187SKrishna.Elango@Sun.COM #ifdef	PRINT_PLX_SEEPROM_CRC
254*10187SKrishna.Elango@Sun.COM 	/* check seeprom CRC to ensure the platform config is right */
255*10187SKrishna.Elango@Sun.COM 	(void) pcieb_print_plx_seeprom_crc_data(pcieb);
256*10187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */
257*10187SKrishna.Elango@Sun.COM }
258*10187SKrishna.Elango@Sun.COM 
259*10187SKrishna.Elango@Sun.COM /*
260*10187SKrishna.Elango@Sun.COM  * These are PLX specific workarounds called during child's initchild.
261*10187SKrishna.Elango@Sun.COM  */
262*10187SKrishna.Elango@Sun.COM int
263*10187SKrishna.Elango@Sun.COM pcieb_init_plx_workarounds(pcieb_devstate_t *pcieb, dev_info_t *child)
264*10187SKrishna.Elango@Sun.COM {
265*10187SKrishna.Elango@Sun.COM 	int		i;
266*10187SKrishna.Elango@Sun.COM 	int		result = DDI_FAILURE;
267*10187SKrishna.Elango@Sun.COM 	uint16_t	reg = 0;
268*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t	config_handle;
269*10187SKrishna.Elango@Sun.COM 	uint16_t	vendor_id =
270*10187SKrishna.Elango@Sun.COM 	    (PCIE_DIP2UPBUS(pcieb->pcieb_dip))->bus_dev_ven_id & 0xFFFF;
271*10187SKrishna.Elango@Sun.COM 
272*10187SKrishna.Elango@Sun.COM 	if (!IS_PLX_VENDORID(vendor_id))
273*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
274*10187SKrishna.Elango@Sun.COM 
275*10187SKrishna.Elango@Sun.COM 	/*
276*10187SKrishna.Elango@Sun.COM 	 * Due to a PLX HW bug, a SW workaround to prevent the chip from
277*10187SKrishna.Elango@Sun.COM 	 * wedging is needed.  SW just needs to tranfer 64 TLPs from
278*10187SKrishna.Elango@Sun.COM 	 * the downstream port to the child device.
279*10187SKrishna.Elango@Sun.COM 	 * The most benign way of doing this is to read the ID register
280*10187SKrishna.Elango@Sun.COM 	 * 64 times.  This SW workaround should have minimum performance
281*10187SKrishna.Elango@Sun.COM 	 * impact and shouldn't cause a problem for all other bridges
282*10187SKrishna.Elango@Sun.COM 	 * and switches.
283*10187SKrishna.Elango@Sun.COM 	 *
284*10187SKrishna.Elango@Sun.COM 	 * The code needs to be written in a way to make sure it isn't
285*10187SKrishna.Elango@Sun.COM 	 * optimized out.
286*10187SKrishna.Elango@Sun.COM 	 */
287*10187SKrishna.Elango@Sun.COM 	if (!pxb_tlp_count) {
288*10187SKrishna.Elango@Sun.COM 		result = DDI_SUCCESS;
289*10187SKrishna.Elango@Sun.COM 		goto done;
290*10187SKrishna.Elango@Sun.COM 	}
291*10187SKrishna.Elango@Sun.COM 
292*10187SKrishna.Elango@Sun.COM 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
293*10187SKrishna.Elango@Sun.COM 		result = DDI_FAILURE;
294*10187SKrishna.Elango@Sun.COM 		goto done;
295*10187SKrishna.Elango@Sun.COM 	}
296*10187SKrishna.Elango@Sun.COM 
297*10187SKrishna.Elango@Sun.COM 	for (i = 0; i < pxb_tlp_count; i += 1)
298*10187SKrishna.Elango@Sun.COM 		reg |= pci_config_get16(config_handle, PCI_CONF_VENID);
299*10187SKrishna.Elango@Sun.COM 
300*10187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE_BDG(PCIE_DIP2BUS(pcieb->pcieb_dip)))
301*10187SKrishna.Elango@Sun.COM 		pcieb_set_pci_perf_parameters(child, config_handle);
302*10187SKrishna.Elango@Sun.COM 
303*10187SKrishna.Elango@Sun.COM 	pci_config_teardown(&config_handle);
304*10187SKrishna.Elango@Sun.COM 	result = DDI_SUCCESS;
305*10187SKrishna.Elango@Sun.COM done:
306*10187SKrishna.Elango@Sun.COM 	return (result);
307*10187SKrishna.Elango@Sun.COM }
308*10187SKrishna.Elango@Sun.COM 
309*10187SKrishna.Elango@Sun.COM /*
310*10187SKrishna.Elango@Sun.COM  * Disable PLX specific relaxed ordering mode.	Due to PLX
311*10187SKrishna.Elango@Sun.COM  * erratum #6, use of this mode with Cut-Through Cancellation
312*10187SKrishna.Elango@Sun.COM  * can result in dropped Completion type packets.
313*10187SKrishna.Elango@Sun.COM  *
314*10187SKrishna.Elango@Sun.COM  * Clear the Relaxed Ordering Mode on 8533 and 8548 switches.
315*10187SKrishna.Elango@Sun.COM  * To disable RO, clear bit 5 in offset 0x664, an undocumented
316*10187SKrishna.Elango@Sun.COM  * bit in the PLX spec, on Ports 0, 8 and 12.  Proprietary PLX
317*10187SKrishna.Elango@Sun.COM  * registers are normally accessible only via memspace from Port
318*10187SKrishna.Elango@Sun.COM  * 0.  If port 0 is attached go ahead and disable RO on Port 0,
319*10187SKrishna.Elango@Sun.COM  * 8 and 12, if they exist.
320*10187SKrishna.Elango@Sun.COM  */
321*10187SKrishna.Elango@Sun.COM static void
322*10187SKrishna.Elango@Sun.COM plx_ro_disable(pcieb_devstate_t *pcieb)
323*10187SKrishna.Elango@Sun.COM {
324*10187SKrishna.Elango@Sun.COM 	pcie_bus_t		*bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip);
325*10187SKrishna.Elango@Sun.COM 	dev_info_t		*dip = pcieb->pcieb_dip;
326*10187SKrishna.Elango@Sun.COM 	uint16_t		device_id = bus_p->bus_dev_ven_id >> 16;
327*10187SKrishna.Elango@Sun.COM 	pci_regspec_t		*reg_spec, *addr_spec;
328*10187SKrishna.Elango@Sun.COM 	int			rlen, alen;
329*10187SKrishna.Elango@Sun.COM 	int			orig_rsize, new_rsize;
330*10187SKrishna.Elango@Sun.COM 	uint_t			rnum, anum;
331*10187SKrishna.Elango@Sun.COM 	ddi_device_acc_attr_t	attr;
332*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t	hdl;
333*10187SKrishna.Elango@Sun.COM 	caddr_t			regsp;
334*10187SKrishna.Elango@Sun.COM 	uint32_t		val, port_enable;
335*10187SKrishna.Elango@Sun.COM 	char			*offset;
336*10187SKrishna.Elango@Sun.COM 	char			*port_offset;
337*10187SKrishna.Elango@Sun.COM 
338*10187SKrishna.Elango@Sun.COM 	if (!((device_id == PXB_DEVICE_PLX_8533) ||
339*10187SKrishna.Elango@Sun.COM 	    (device_id == PXB_DEVICE_PLX_8548)))
340*10187SKrishna.Elango@Sun.COM 		return;
341*10187SKrishna.Elango@Sun.COM 
342*10187SKrishna.Elango@Sun.COM 	/* You can also only do this on Port 0 */
343*10187SKrishna.Elango@Sun.COM 	val = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
344*10187SKrishna.Elango@Sun.COM 	val = (val >> PCIE_LINKCAP_PORT_NUMBER_SHIFT) &
345*10187SKrishna.Elango@Sun.COM 	    PCIE_LINKCAP_PORT_NUMBER_MASK;
346*10187SKrishna.Elango@Sun.COM 
347*10187SKrishna.Elango@Sun.COM 	PCIEB_DEBUG(DBG_ATTACH, dip, "PLX RO Disable : bdf=0x%x port=%d\n",
348*10187SKrishna.Elango@Sun.COM 	    bus_p->bus_bdf, val);
349*10187SKrishna.Elango@Sun.COM 
350*10187SKrishna.Elango@Sun.COM 	if (val != 0)
351*10187SKrishna.Elango@Sun.COM 		return;
352*10187SKrishna.Elango@Sun.COM 
353*10187SKrishna.Elango@Sun.COM 	/*
354*10187SKrishna.Elango@Sun.COM 	 * Read the reg property, but allocate extra space incase we need to add
355*10187SKrishna.Elango@Sun.COM 	 * a new entry later.
356*10187SKrishna.Elango@Sun.COM 	 */
357*10187SKrishna.Elango@Sun.COM 	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
358*10187SKrishna.Elango@Sun.COM 	    &orig_rsize) != DDI_SUCCESS)
359*10187SKrishna.Elango@Sun.COM 		return;
360*10187SKrishna.Elango@Sun.COM 
361*10187SKrishna.Elango@Sun.COM 	new_rsize = orig_rsize + sizeof (pci_regspec_t);
362*10187SKrishna.Elango@Sun.COM 	reg_spec = kmem_alloc(new_rsize, KM_SLEEP);
363*10187SKrishna.Elango@Sun.COM 
364*10187SKrishna.Elango@Sun.COM 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
365*10187SKrishna.Elango@Sun.COM 	    (caddr_t)reg_spec, &orig_rsize) != DDI_SUCCESS)
366*10187SKrishna.Elango@Sun.COM 		goto fail;
367*10187SKrishna.Elango@Sun.COM 
368*10187SKrishna.Elango@Sun.COM 	/* Find the mem32 reg property */
369*10187SKrishna.Elango@Sun.COM 	rlen = orig_rsize / sizeof (pci_regspec_t);
370*10187SKrishna.Elango@Sun.COM 	for (rnum = 0; rnum < rlen; rnum++) {
371*10187SKrishna.Elango@Sun.COM 		if ((reg_spec[rnum].pci_phys_hi & PCI_ADDR_MASK) ==
372*10187SKrishna.Elango@Sun.COM 		    PCI_ADDR_MEM32)
373*10187SKrishna.Elango@Sun.COM 			goto fix;
374*10187SKrishna.Elango@Sun.COM 	}
375*10187SKrishna.Elango@Sun.COM 
376*10187SKrishna.Elango@Sun.COM 	/*
377*10187SKrishna.Elango@Sun.COM 	 * Mem32 reg property was not found.
378*10187SKrishna.Elango@Sun.COM 	 * Look for it in assign-address property.
379*10187SKrishna.Elango@Sun.COM 	 */
380*10187SKrishna.Elango@Sun.COM 	addr_spec = bus_p->bus_assigned_addr;
381*10187SKrishna.Elango@Sun.COM 	alen = bus_p->bus_assigned_entries;
382*10187SKrishna.Elango@Sun.COM 	for (anum = 0; anum < alen; anum++) {
383*10187SKrishna.Elango@Sun.COM 		if ((addr_spec[anum].pci_phys_hi & PCI_ADDR_MASK) ==
384*10187SKrishna.Elango@Sun.COM 		    PCI_ADDR_MEM32)
385*10187SKrishna.Elango@Sun.COM 			goto update;
386*10187SKrishna.Elango@Sun.COM 	}
387*10187SKrishna.Elango@Sun.COM 
388*10187SKrishna.Elango@Sun.COM 	/* Unable to find mem space assigned address, give up. */
389*10187SKrishna.Elango@Sun.COM 	goto fail;
390*10187SKrishna.Elango@Sun.COM 
391*10187SKrishna.Elango@Sun.COM update:
392*10187SKrishna.Elango@Sun.COM 	/*
393*10187SKrishna.Elango@Sun.COM 	 * Add the mem32 access to the reg spec.
394*10187SKrishna.Elango@Sun.COM 	 * Use the last entry which was previously allocated.
395*10187SKrishna.Elango@Sun.COM 	 */
396*10187SKrishna.Elango@Sun.COM 	reg_spec[rnum].pci_phys_hi = (addr_spec[anum].pci_phys_hi &
397*10187SKrishna.Elango@Sun.COM 	    ~PCI_REG_REL_M);
398*10187SKrishna.Elango@Sun.COM 	reg_spec[rnum].pci_phys_mid = 0;
399*10187SKrishna.Elango@Sun.COM 	reg_spec[rnum].pci_phys_low = 0;
400*10187SKrishna.Elango@Sun.COM 	reg_spec[rnum].pci_size_hi = addr_spec[anum].pci_size_hi;
401*10187SKrishna.Elango@Sun.COM 	reg_spec[rnum].pci_size_low = addr_spec[anum].pci_size_low;
402*10187SKrishna.Elango@Sun.COM 
403*10187SKrishna.Elango@Sun.COM 	/* Create the new reg_spec data and update the property */
404*10187SKrishna.Elango@Sun.COM 	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
405*10187SKrishna.Elango@Sun.COM 	    (int *)reg_spec, (new_rsize / sizeof (int))) != DDI_SUCCESS)
406*10187SKrishna.Elango@Sun.COM 		goto fail;
407*10187SKrishna.Elango@Sun.COM 
408*10187SKrishna.Elango@Sun.COM fix:
409*10187SKrishna.Elango@Sun.COM 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
410*10187SKrishna.Elango@Sun.COM 	attr.devacc_attr_endian_flags  = DDI_STRUCTURE_LE_ACC;
411*10187SKrishna.Elango@Sun.COM 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
412*10187SKrishna.Elango@Sun.COM 
413*10187SKrishna.Elango@Sun.COM 	if (ddi_regs_map_setup(dip, rnum, &regsp, 0, 0, &attr,
414*10187SKrishna.Elango@Sun.COM 	    &hdl) != DDI_SUCCESS)
415*10187SKrishna.Elango@Sun.COM 		goto fail;
416*10187SKrishna.Elango@Sun.COM 
417*10187SKrishna.Elango@Sun.COM 	/* Grab register which shows which ports are enabled */
418*10187SKrishna.Elango@Sun.COM 	offset = (char *)regsp + PLX_INGRESS_PORT_ENABLE;
419*10187SKrishna.Elango@Sun.COM 	port_enable = ddi_get32(hdl, (uint32_t *)offset);
420*10187SKrishna.Elango@Sun.COM 
421*10187SKrishna.Elango@Sun.COM 	if ((port_enable == 0xFFFFFFFF) || (port_enable == 0))
422*10187SKrishna.Elango@Sun.COM 		goto done;
423*10187SKrishna.Elango@Sun.COM 
424*10187SKrishna.Elango@Sun.COM 	offset = (char *)regsp + PLX_INGRESS_CONTROL_SHADOW;
425*10187SKrishna.Elango@Sun.COM 
426*10187SKrishna.Elango@Sun.COM 	/* Disable RO on Port 0 */
427*10187SKrishna.Elango@Sun.COM 	port_offset = 0x0 + offset;
428*10187SKrishna.Elango@Sun.COM 	val = ddi_get32(hdl, (uint32_t *)port_offset);
429*10187SKrishna.Elango@Sun.COM 	if (val & PLX_RO_MODE_BIT)
430*10187SKrishna.Elango@Sun.COM 		val ^= PLX_RO_MODE_BIT;
431*10187SKrishna.Elango@Sun.COM 	ddi_put32(hdl, (uint32_t *)port_offset, val);
432*10187SKrishna.Elango@Sun.COM 
433*10187SKrishna.Elango@Sun.COM 	/* Disable RO on Port 8, but make sure its enabled */
434*10187SKrishna.Elango@Sun.COM 	if (!(port_enable & (1 << 8)))
435*10187SKrishna.Elango@Sun.COM 		goto port12;
436*10187SKrishna.Elango@Sun.COM 
437*10187SKrishna.Elango@Sun.COM 	port_offset = (8 * 0x1000) + offset;
438*10187SKrishna.Elango@Sun.COM 	val = ddi_get32(hdl, (uint32_t *)port_offset);
439*10187SKrishna.Elango@Sun.COM 	if (val & PLX_RO_MODE_BIT)
440*10187SKrishna.Elango@Sun.COM 		val ^= PLX_RO_MODE_BIT;
441*10187SKrishna.Elango@Sun.COM 	ddi_put32(hdl, (uint32_t *)port_offset, val);
442*10187SKrishna.Elango@Sun.COM 
443*10187SKrishna.Elango@Sun.COM port12:
444*10187SKrishna.Elango@Sun.COM 	/* Disable RO on Port 12, but make sure it exists */
445*10187SKrishna.Elango@Sun.COM 	if (!(port_enable & (1 << 12)))
446*10187SKrishna.Elango@Sun.COM 		goto done;
447*10187SKrishna.Elango@Sun.COM 
448*10187SKrishna.Elango@Sun.COM 	port_offset = (12 * 0x1000) + offset;
449*10187SKrishna.Elango@Sun.COM 	val = ddi_get32(hdl, (uint32_t *)port_offset);
450*10187SKrishna.Elango@Sun.COM 	if (val & PLX_RO_MODE_BIT)
451*10187SKrishna.Elango@Sun.COM 		val ^= PLX_RO_MODE_BIT;
452*10187SKrishna.Elango@Sun.COM 	ddi_put32(hdl, (uint32_t *)port_offset, val);
453*10187SKrishna.Elango@Sun.COM 
454*10187SKrishna.Elango@Sun.COM 	goto done;
455*10187SKrishna.Elango@Sun.COM 
456*10187SKrishna.Elango@Sun.COM done:
457*10187SKrishna.Elango@Sun.COM 	ddi_regs_map_free(&hdl);
458*10187SKrishna.Elango@Sun.COM fail:
459*10187SKrishna.Elango@Sun.COM 	kmem_free(reg_spec, new_rsize);
460*10187SKrishna.Elango@Sun.COM }
461*10187SKrishna.Elango@Sun.COM 
462*10187SKrishna.Elango@Sun.COM #ifdef	PRINT_PLX_SEEPROM_CRC
463*10187SKrishna.Elango@Sun.COM static void
464*10187SKrishna.Elango@Sun.COM pcieb_print_plx_seeprom_crc_data(pcieb_devstate_t *pcieb_p)
465*10187SKrishna.Elango@Sun.COM {
466*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t h;
467*10187SKrishna.Elango@Sun.COM 	dev_info_t *dip = pcieb_p->pcieb_dip;
468*10187SKrishna.Elango@Sun.COM 	uint16_t vendorid = (PCIE_DIP2BUS(dip)->bus_dev_ven_id) & 0xFFFF;
469*10187SKrishna.Elango@Sun.COM 	int nregs;
470*10187SKrishna.Elango@Sun.COM 	caddr_t mp;
471*10187SKrishna.Elango@Sun.COM 	off_t bar_size;
472*10187SKrishna.Elango@Sun.COM 	ddi_device_acc_attr_t mattr = {
473*10187SKrishna.Elango@Sun.COM 		DDI_DEVICE_ATTR_V0,
474*10187SKrishna.Elango@Sun.COM 		DDI_STRUCTURE_LE_ACC,
475*10187SKrishna.Elango@Sun.COM 		DDI_STRICTORDER_ACC
476*10187SKrishna.Elango@Sun.COM 	};
477*10187SKrishna.Elango@Sun.COM 	uint32_t addr_reg_off = 0x260, data_reg_off = 0x264, data = 0x6BE4;
478*10187SKrishna.Elango@Sun.COM 
479*10187SKrishna.Elango@Sun.COM 	if (vendorid != PXB_VENDOR_PLX)
480*10187SKrishna.Elango@Sun.COM 		return;
481*10187SKrishna.Elango@Sun.COM 	if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
482*10187SKrishna.Elango@Sun.COM 		return;
483*10187SKrishna.Elango@Sun.COM 	if (nregs < 2)	/* check for CONF entry only, no BARs */
484*10187SKrishna.Elango@Sun.COM 		return;
485*10187SKrishna.Elango@Sun.COM 	if (ddi_dev_regsize(dip, 1, &bar_size) != DDI_SUCCESS)
486*10187SKrishna.Elango@Sun.COM 		return;
487*10187SKrishna.Elango@Sun.COM 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&mp, 0, bar_size,
488*10187SKrishna.Elango@Sun.COM 	    &mattr, &h) != DDI_SUCCESS)
489*10187SKrishna.Elango@Sun.COM 		return;
490*10187SKrishna.Elango@Sun.COM 	ddi_put32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off), data);
491*10187SKrishna.Elango@Sun.COM 	delay(drv_usectohz(1000000));
492*10187SKrishna.Elango@Sun.COM 	printf("%s#%d: EEPROM StatusReg = %x, CRC = %x\n",
493*10187SKrishna.Elango@Sun.COM 	    ddi_driver_name(dip), ddi_get_instance(dip),
494*10187SKrishna.Elango@Sun.COM 	    ddi_get32(h, (uint32_t *)((uchar_t *)mp + addr_reg_off)),
495*10187SKrishna.Elango@Sun.COM 	    ddi_get32(h, (uint32_t *)((uchar_t *)mp + data_reg_off)));
496*10187SKrishna.Elango@Sun.COM #ifdef PLX_HOT_RESET_DISABLE
497*10187SKrishna.Elango@Sun.COM 	/* prevent hot reset from propogating downstream. */
498*10187SKrishna.Elango@Sun.COM 	data = ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC));
499*10187SKrishna.Elango@Sun.COM 	ddi_put32(h, (uint32_t *)((uchar_t *)mp + 0x1DC), data | 0x80000);
500*10187SKrishna.Elango@Sun.COM 	delay(drv_usectohz(1000000));
501*10187SKrishna.Elango@Sun.COM 	printf("%s#%d: EEPROM 0x1DC prewrite=%x postwrite=%x\n",
502*10187SKrishna.Elango@Sun.COM 	    ddi_driver_name(dip), ddi_get_instance(dip), data,
503*10187SKrishna.Elango@Sun.COM 	    ddi_get32(h, (uint32_t *)((uchar_t *)mp + 0x1DC)));
504*10187SKrishna.Elango@Sun.COM #endif /* PLX_HOT_RESET_DISABLE */
505*10187SKrishna.Elango@Sun.COM 	ddi_regs_map_free(&h);
506*10187SKrishna.Elango@Sun.COM }
507*10187SKrishna.Elango@Sun.COM #endif /* PRINT_PLX_SEEPROM_CRC */
508*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */
509