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