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