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