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