Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.3 560 lines 15 kB view raw
1/* 2 * File: portdrv_core.c 3 * Purpose: PCI Express Port Bus Driver's Core Functions 4 * 5 * Copyright (C) 2004 Intel 6 * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) 7 */ 8 9#include <linux/module.h> 10#include <linux/pci.h> 11#include <linux/kernel.h> 12#include <linux/errno.h> 13#include <linux/pm.h> 14#include <linux/string.h> 15#include <linux/slab.h> 16#include <linux/pcieport_if.h> 17#include <linux/aer.h> 18 19#include "../pci.h" 20#include "portdrv.h" 21 22/** 23 * release_pcie_device - free PCI Express port service device structure 24 * @dev: Port service device to release 25 * 26 * Invoked automatically when device is being removed in response to 27 * device_unregister(dev). Release all resources being claimed. 28 */ 29static void release_pcie_device(struct device *dev) 30{ 31 kfree(to_pcie_device(dev)); 32} 33 34/** 35 * pcie_port_msix_add_entry - add entry to given array of MSI-X entries 36 * @entries: Array of MSI-X entries 37 * @new_entry: Index of the entry to add to the array 38 * @nr_entries: Number of entries aleady in the array 39 * 40 * Return value: Position of the added entry in the array 41 */ 42static int pcie_port_msix_add_entry( 43 struct msix_entry *entries, int new_entry, int nr_entries) 44{ 45 int j; 46 47 for (j = 0; j < nr_entries; j++) 48 if (entries[j].entry == new_entry) 49 return j; 50 51 entries[j].entry = new_entry; 52 return j; 53} 54 55/** 56 * pcie_port_enable_msix - try to set up MSI-X as interrupt mode for given port 57 * @dev: PCI Express port to handle 58 * @vectors: Array of interrupt vectors to populate 59 * @mask: Bitmask of port capabilities returned by get_port_device_capability() 60 * 61 * Return value: 0 on success, error code on failure 62 */ 63static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) 64{ 65 struct msix_entry *msix_entries; 66 int idx[PCIE_PORT_DEVICE_MAXSERVICES]; 67 int nr_entries, status, pos, i, nvec; 68 u16 reg16; 69 u32 reg32; 70 71 nr_entries = pci_msix_table_size(dev); 72 if (!nr_entries) 73 return -EINVAL; 74 if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES) 75 nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES; 76 77 msix_entries = kzalloc(sizeof(*msix_entries) * nr_entries, GFP_KERNEL); 78 if (!msix_entries) 79 return -ENOMEM; 80 81 /* 82 * Allocate as many entries as the port wants, so that we can check 83 * which of them will be useful. Moreover, if nr_entries is correctly 84 * equal to the number of entries this port actually uses, we'll happily 85 * go through without any tricks. 86 */ 87 for (i = 0; i < nr_entries; i++) 88 msix_entries[i].entry = i; 89 90 status = pci_enable_msix(dev, msix_entries, nr_entries); 91 if (status) 92 goto Exit; 93 94 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) 95 idx[i] = -1; 96 status = -EIO; 97 nvec = 0; 98 99 if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) { 100 int entry; 101 102 /* 103 * The code below follows the PCI Express Base Specification 2.0 104 * stating in Section 6.1.6 that "PME and Hot-Plug Event 105 * interrupts (when both are implemented) always share the same 106 * MSI or MSI-X vector, as indicated by the Interrupt Message 107 * Number field in the PCI Express Capabilities register", where 108 * according to Section 7.8.2 of the specification "For MSI-X, 109 * the value in this field indicates which MSI-X Table entry is 110 * used to generate the interrupt message." 111 */ 112 pos = pci_pcie_cap(dev); 113 pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16); 114 entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9; 115 if (entry >= nr_entries) 116 goto Error; 117 118 i = pcie_port_msix_add_entry(msix_entries, entry, nvec); 119 if (i == nvec) 120 nvec++; 121 122 idx[PCIE_PORT_SERVICE_PME_SHIFT] = i; 123 idx[PCIE_PORT_SERVICE_HP_SHIFT] = i; 124 } 125 126 if (mask & PCIE_PORT_SERVICE_AER) { 127 int entry; 128 129 /* 130 * The code below follows Section 7.10.10 of the PCI Express 131 * Base Specification 2.0 stating that bits 31-27 of the Root 132 * Error Status Register contain a value indicating which of the 133 * MSI/MSI-X vectors assigned to the port is going to be used 134 * for AER, where "For MSI-X, the value in this register 135 * indicates which MSI-X Table entry is used to generate the 136 * interrupt message." 137 */ 138 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 139 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32); 140 entry = reg32 >> 27; 141 if (entry >= nr_entries) 142 goto Error; 143 144 i = pcie_port_msix_add_entry(msix_entries, entry, nvec); 145 if (i == nvec) 146 nvec++; 147 148 idx[PCIE_PORT_SERVICE_AER_SHIFT] = i; 149 } 150 151 /* 152 * If nvec is equal to the allocated number of entries, we can just use 153 * what we have. Otherwise, the port has some extra entries not for the 154 * services we know and we need to work around that. 155 */ 156 if (nvec == nr_entries) { 157 status = 0; 158 } else { 159 /* Drop the temporary MSI-X setup */ 160 pci_disable_msix(dev); 161 162 /* Now allocate the MSI-X vectors for real */ 163 status = pci_enable_msix(dev, msix_entries, nvec); 164 if (status) 165 goto Exit; 166 } 167 168 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) 169 vectors[i] = idx[i] >= 0 ? msix_entries[idx[i]].vector : -1; 170 171 Exit: 172 kfree(msix_entries); 173 return status; 174 175 Error: 176 pci_disable_msix(dev); 177 goto Exit; 178} 179 180/** 181 * init_service_irqs - initialize irqs for PCI Express port services 182 * @dev: PCI Express port to handle 183 * @irqs: Array of irqs to populate 184 * @mask: Bitmask of port capabilities returned by get_port_device_capability() 185 * 186 * Return value: Interrupt mode associated with the port 187 */ 188static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask) 189{ 190 int i, irq = -1; 191 192 /* We have to use INTx if MSI cannot be used for PCIe PME. */ 193 if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) { 194 if (dev->pin) 195 irq = dev->irq; 196 goto no_msi; 197 } 198 199 /* Try to use MSI-X if supported */ 200 if (!pcie_port_enable_msix(dev, irqs, mask)) 201 return 0; 202 203 /* We're not going to use MSI-X, so try MSI and fall back to INTx */ 204 if (!pci_enable_msi(dev) || dev->pin) 205 irq = dev->irq; 206 207 no_msi: 208 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) 209 irqs[i] = irq; 210 irqs[PCIE_PORT_SERVICE_VC_SHIFT] = -1; 211 212 if (irq < 0) 213 return -ENODEV; 214 return 0; 215} 216 217static void cleanup_service_irqs(struct pci_dev *dev) 218{ 219 if (dev->msix_enabled) 220 pci_disable_msix(dev); 221 else if (dev->msi_enabled) 222 pci_disable_msi(dev); 223} 224 225/** 226 * get_port_device_capability - discover capabilities of a PCI Express port 227 * @dev: PCI Express port to examine 228 * 229 * The capabilities are read from the port's PCI Express configuration registers 230 * as described in PCI Express Base Specification 1.0a sections 7.8.2, 7.8.9 and 231 * 7.9 - 7.11. 232 * 233 * Return value: Bitmask of discovered port capabilities 234 */ 235static int get_port_device_capability(struct pci_dev *dev) 236{ 237 int services = 0, pos; 238 u16 reg16; 239 u32 reg32; 240 int cap_mask; 241 int err; 242 243 if (pcie_ports_disabled) 244 return 0; 245 246 err = pcie_port_platform_notify(dev, &cap_mask); 247 if (!pcie_ports_auto) { 248 cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP 249 | PCIE_PORT_SERVICE_VC; 250 if (pci_aer_available()) 251 cap_mask |= PCIE_PORT_SERVICE_AER; 252 } else if (err) { 253 return 0; 254 } 255 256 pos = pci_pcie_cap(dev); 257 pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16); 258 /* Hot-Plug Capable */ 259 if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) { 260 pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32); 261 if (reg32 & PCI_EXP_SLTCAP_HPC) { 262 services |= PCIE_PORT_SERVICE_HP; 263 /* 264 * Disable hot-plug interrupts in case they have been 265 * enabled by the BIOS and the hot-plug service driver 266 * is not loaded. 267 */ 268 pos += PCI_EXP_SLTCTL; 269 pci_read_config_word(dev, pos, &reg16); 270 reg16 &= ~(PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_HPIE); 271 pci_write_config_word(dev, pos, reg16); 272 } 273 } 274 /* AER capable */ 275 if ((cap_mask & PCIE_PORT_SERVICE_AER) 276 && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) { 277 services |= PCIE_PORT_SERVICE_AER; 278 /* 279 * Disable AER on this port in case it's been enabled by the 280 * BIOS (the AER service driver will enable it when necessary). 281 */ 282 pci_disable_pcie_error_reporting(dev); 283 } 284 /* VC support */ 285 if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) 286 services |= PCIE_PORT_SERVICE_VC; 287 /* Root ports are capable of generating PME too */ 288 if ((cap_mask & PCIE_PORT_SERVICE_PME) 289 && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { 290 services |= PCIE_PORT_SERVICE_PME; 291 /* 292 * Disable PME interrupt on this port in case it's been enabled 293 * by the BIOS (the PME service driver will enable it when 294 * necessary). 295 */ 296 pcie_pme_interrupt_enable(dev, false); 297 } 298 299 return services; 300} 301 302/** 303 * pcie_device_init - allocate and initialize PCI Express port service device 304 * @pdev: PCI Express port to associate the service device with 305 * @service: Type of service to associate with the service device 306 * @irq: Interrupt vector to associate with the service device 307 */ 308static int pcie_device_init(struct pci_dev *pdev, int service, int irq) 309{ 310 int retval; 311 struct pcie_device *pcie; 312 struct device *device; 313 314 pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); 315 if (!pcie) 316 return -ENOMEM; 317 pcie->port = pdev; 318 pcie->irq = irq; 319 pcie->service = service; 320 321 /* Initialize generic device interface */ 322 device = &pcie->device; 323 device->bus = &pcie_port_bus_type; 324 device->release = release_pcie_device; /* callback to free pcie dev */ 325 dev_set_name(device, "%s:pcie%02x", 326 pci_name(pdev), 327 get_descriptor_id(pdev->pcie_type, service)); 328 device->parent = &pdev->dev; 329 device_enable_async_suspend(device); 330 331 retval = device_register(device); 332 if (retval) 333 kfree(pcie); 334 else 335 get_device(device); 336 return retval; 337} 338 339/** 340 * pcie_port_device_register - register PCI Express port 341 * @dev: PCI Express port to register 342 * 343 * Allocate the port extension structure and register services associated with 344 * the port. 345 */ 346int pcie_port_device_register(struct pci_dev *dev) 347{ 348 int status, capabilities, i, nr_service; 349 int irqs[PCIE_PORT_DEVICE_MAXSERVICES]; 350 351 /* Enable PCI Express port device */ 352 status = pci_enable_device(dev); 353 if (status) 354 return status; 355 356 /* Get and check PCI Express port services */ 357 capabilities = get_port_device_capability(dev); 358 if (!capabilities) 359 return 0; 360 361 pci_set_master(dev); 362 /* 363 * Initialize service irqs. Don't use service devices that 364 * require interrupts if there is no way to generate them. 365 */ 366 status = init_service_irqs(dev, irqs, capabilities); 367 if (status) { 368 capabilities &= PCIE_PORT_SERVICE_VC; 369 if (!capabilities) 370 goto error_disable; 371 } 372 373 /* Allocate child services if any */ 374 status = -ENODEV; 375 nr_service = 0; 376 for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { 377 int service = 1 << i; 378 if (!(capabilities & service)) 379 continue; 380 if (!pcie_device_init(dev, service, irqs[i])) 381 nr_service++; 382 } 383 if (!nr_service) 384 goto error_cleanup_irqs; 385 386 return 0; 387 388error_cleanup_irqs: 389 cleanup_service_irqs(dev); 390error_disable: 391 pci_disable_device(dev); 392 return status; 393} 394 395#ifdef CONFIG_PM 396static int suspend_iter(struct device *dev, void *data) 397{ 398 struct pcie_port_service_driver *service_driver; 399 400 if ((dev->bus == &pcie_port_bus_type) && dev->driver) { 401 service_driver = to_service_driver(dev->driver); 402 if (service_driver->suspend) 403 service_driver->suspend(to_pcie_device(dev)); 404 } 405 return 0; 406} 407 408/** 409 * pcie_port_device_suspend - suspend port services associated with a PCIe port 410 * @dev: PCI Express port to handle 411 */ 412int pcie_port_device_suspend(struct device *dev) 413{ 414 return device_for_each_child(dev, NULL, suspend_iter); 415} 416 417static int resume_iter(struct device *dev, void *data) 418{ 419 struct pcie_port_service_driver *service_driver; 420 421 if ((dev->bus == &pcie_port_bus_type) && 422 (dev->driver)) { 423 service_driver = to_service_driver(dev->driver); 424 if (service_driver->resume) 425 service_driver->resume(to_pcie_device(dev)); 426 } 427 return 0; 428} 429 430/** 431 * pcie_port_device_suspend - resume port services associated with a PCIe port 432 * @dev: PCI Express port to handle 433 */ 434int pcie_port_device_resume(struct device *dev) 435{ 436 return device_for_each_child(dev, NULL, resume_iter); 437} 438#endif /* PM */ 439 440static int remove_iter(struct device *dev, void *data) 441{ 442 if (dev->bus == &pcie_port_bus_type) { 443 put_device(dev); 444 device_unregister(dev); 445 } 446 return 0; 447} 448 449/** 450 * pcie_port_device_remove - unregister PCI Express port service devices 451 * @dev: PCI Express port the service devices to unregister are associated with 452 * 453 * Remove PCI Express port service devices associated with given port and 454 * disable MSI-X or MSI for the port. 455 */ 456void pcie_port_device_remove(struct pci_dev *dev) 457{ 458 device_for_each_child(&dev->dev, NULL, remove_iter); 459 cleanup_service_irqs(dev); 460 pci_disable_device(dev); 461} 462 463/** 464 * pcie_port_probe_service - probe driver for given PCI Express port service 465 * @dev: PCI Express port service device to probe against 466 * 467 * If PCI Express port service driver is registered with 468 * pcie_port_service_register(), this function will be called by the driver core 469 * whenever match is found between the driver and a port service device. 470 */ 471static int pcie_port_probe_service(struct device *dev) 472{ 473 struct pcie_device *pciedev; 474 struct pcie_port_service_driver *driver; 475 int status; 476 477 if (!dev || !dev->driver) 478 return -ENODEV; 479 480 driver = to_service_driver(dev->driver); 481 if (!driver || !driver->probe) 482 return -ENODEV; 483 484 pciedev = to_pcie_device(dev); 485 status = driver->probe(pciedev); 486 if (!status) { 487 dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n", 488 driver->name); 489 get_device(dev); 490 } 491 return status; 492} 493 494/** 495 * pcie_port_remove_service - detach driver from given PCI Express port service 496 * @dev: PCI Express port service device to handle 497 * 498 * If PCI Express port service driver is registered with 499 * pcie_port_service_register(), this function will be called by the driver core 500 * when device_unregister() is called for the port service device associated 501 * with the driver. 502 */ 503static int pcie_port_remove_service(struct device *dev) 504{ 505 struct pcie_device *pciedev; 506 struct pcie_port_service_driver *driver; 507 508 if (!dev || !dev->driver) 509 return 0; 510 511 pciedev = to_pcie_device(dev); 512 driver = to_service_driver(dev->driver); 513 if (driver && driver->remove) { 514 dev_printk(KERN_DEBUG, dev, "unloading service driver %s\n", 515 driver->name); 516 driver->remove(pciedev); 517 put_device(dev); 518 } 519 return 0; 520} 521 522/** 523 * pcie_port_shutdown_service - shut down given PCI Express port service 524 * @dev: PCI Express port service device to handle 525 * 526 * If PCI Express port service driver is registered with 527 * pcie_port_service_register(), this function will be called by the driver core 528 * when device_shutdown() is called for the port service device associated 529 * with the driver. 530 */ 531static void pcie_port_shutdown_service(struct device *dev) {} 532 533/** 534 * pcie_port_service_register - register PCI Express port service driver 535 * @new: PCI Express port service driver to register 536 */ 537int pcie_port_service_register(struct pcie_port_service_driver *new) 538{ 539 if (pcie_ports_disabled) 540 return -ENODEV; 541 542 new->driver.name = (char *)new->name; 543 new->driver.bus = &pcie_port_bus_type; 544 new->driver.probe = pcie_port_probe_service; 545 new->driver.remove = pcie_port_remove_service; 546 new->driver.shutdown = pcie_port_shutdown_service; 547 548 return driver_register(&new->driver); 549} 550EXPORT_SYMBOL(pcie_port_service_register); 551 552/** 553 * pcie_port_service_unregister - unregister PCI Express port service driver 554 * @drv: PCI Express port service driver to unregister 555 */ 556void pcie_port_service_unregister(struct pcie_port_service_driver *drv) 557{ 558 driver_unregister(&drv->driver); 559} 560EXPORT_SYMBOL(pcie_port_service_unregister);