1/* 2 * File: portdrv_pci.c 3 * Purpose: PCI Express Port Bus Driver 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/init.h> 15#include <linux/pcieport_if.h> 16#include <linux/aer.h> 17#include <linux/dmi.h> 18#include <linux/pci-aspm.h> 19 20#include "portdrv.h" 21#include "aer/aerdrv.h" 22 23/* 24 * Version Information 25 */ 26#define DRIVER_VERSION "v1.0" 27#define DRIVER_AUTHOR "tom.l.nguyen@intel.com" 28#define DRIVER_DESC "PCIe Port Bus Driver" 29MODULE_AUTHOR(DRIVER_AUTHOR); 30MODULE_DESCRIPTION(DRIVER_DESC); 31MODULE_LICENSE("GPL"); 32 33/* If this switch is set, PCIe port native services should not be enabled. */ 34bool pcie_ports_disabled; 35 36/* 37 * If this switch is set, ACPI _OSC will be used to determine whether or not to 38 * enable PCIe port native services. 39 */ 40bool pcie_ports_auto = true; 41 42static int __init pcie_port_setup(char *str) 43{ 44 if (!strncmp(str, "compat", 6)) { 45 pcie_ports_disabled = true; 46 } else if (!strncmp(str, "native", 6)) { 47 pcie_ports_disabled = false; 48 pcie_ports_auto = false; 49 } else if (!strncmp(str, "auto", 4)) { 50 pcie_ports_disabled = false; 51 pcie_ports_auto = true; 52 } 53 54 return 1; 55} 56__setup("pcie_ports=", pcie_port_setup); 57 58/* global data */ 59 60static int pcie_portdrv_restore_config(struct pci_dev *dev) 61{ 62 int retval; 63 64 retval = pci_enable_device(dev); 65 if (retval) 66 return retval; 67 pci_set_master(dev); 68 return 0; 69} 70 71#ifdef CONFIG_PM 72static const struct dev_pm_ops pcie_portdrv_pm_ops = { 73 .suspend = pcie_port_device_suspend, 74 .resume = pcie_port_device_resume, 75 .freeze = pcie_port_device_suspend, 76 .thaw = pcie_port_device_resume, 77 .poweroff = pcie_port_device_suspend, 78 .restore = pcie_port_device_resume, 79}; 80 81#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) 82 83#else /* !PM */ 84 85#define PCIE_PORTDRV_PM_OPS NULL 86#endif /* !PM */ 87 88/* 89 * pcie_portdrv_probe - Probe PCI-Express port devices 90 * @dev: PCI-Express port device being probed 91 * 92 * If detected invokes the pcie_port_device_register() method for 93 * this port device. 94 * 95 */ 96static int __devinit pcie_portdrv_probe(struct pci_dev *dev, 97 const struct pci_device_id *id) 98{ 99 int status; 100 101 if (!pci_is_pcie(dev) || 102 ((dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && 103 (dev->pcie_type != PCI_EXP_TYPE_UPSTREAM) && 104 (dev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))) 105 return -ENODEV; 106 107 if (!dev->irq && dev->pin) { 108 dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; " 109 "check vendor BIOS\n", dev->vendor, dev->device); 110 } 111 status = pcie_port_device_register(dev); 112 if (status) 113 return status; 114 115 pci_save_state(dev); 116 117 return 0; 118} 119 120static void pcie_portdrv_remove(struct pci_dev *dev) 121{ 122 pcie_port_device_remove(dev); 123 pci_disable_device(dev); 124} 125 126static int error_detected_iter(struct device *device, void *data) 127{ 128 struct pcie_device *pcie_device; 129 struct pcie_port_service_driver *driver; 130 struct aer_broadcast_data *result_data; 131 pci_ers_result_t status; 132 133 result_data = (struct aer_broadcast_data *) data; 134 135 if (device->bus == &pcie_port_bus_type && device->driver) { 136 driver = to_service_driver(device->driver); 137 if (!driver || 138 !driver->err_handler || 139 !driver->err_handler->error_detected) 140 return 0; 141 142 pcie_device = to_pcie_device(device); 143 144 /* Forward error detected message to service drivers */ 145 status = driver->err_handler->error_detected( 146 pcie_device->port, 147 result_data->state); 148 result_data->result = 149 merge_result(result_data->result, status); 150 } 151 152 return 0; 153} 154 155static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, 156 enum pci_channel_state error) 157{ 158 struct aer_broadcast_data data = {error, PCI_ERS_RESULT_CAN_RECOVER}; 159 int ret; 160 161 /* can not fail */ 162 ret = device_for_each_child(&dev->dev, &data, error_detected_iter); 163 164 return data.result; 165} 166 167static int mmio_enabled_iter(struct device *device, void *data) 168{ 169 struct pcie_device *pcie_device; 170 struct pcie_port_service_driver *driver; 171 pci_ers_result_t status, *result; 172 173 result = (pci_ers_result_t *) data; 174 175 if (device->bus == &pcie_port_bus_type && device->driver) { 176 driver = to_service_driver(device->driver); 177 if (driver && 178 driver->err_handler && 179 driver->err_handler->mmio_enabled) { 180 pcie_device = to_pcie_device(device); 181 182 /* Forward error message to service drivers */ 183 status = driver->err_handler->mmio_enabled( 184 pcie_device->port); 185 *result = merge_result(*result, status); 186 } 187 } 188 189 return 0; 190} 191 192static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) 193{ 194 pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 195 int retval; 196 197 /* get true return value from &status */ 198 retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter); 199 return status; 200} 201 202static int slot_reset_iter(struct device *device, void *data) 203{ 204 struct pcie_device *pcie_device; 205 struct pcie_port_service_driver *driver; 206 pci_ers_result_t status, *result; 207 208 result = (pci_ers_result_t *) data; 209 210 if (device->bus == &pcie_port_bus_type && device->driver) { 211 driver = to_service_driver(device->driver); 212 if (driver && 213 driver->err_handler && 214 driver->err_handler->slot_reset) { 215 pcie_device = to_pcie_device(device); 216 217 /* Forward error message to service drivers */ 218 status = driver->err_handler->slot_reset( 219 pcie_device->port); 220 *result = merge_result(*result, status); 221 } 222 } 223 224 return 0; 225} 226 227static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) 228{ 229 pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 230 int retval; 231 232 /* If fatal, restore cfg space for possible link reset at upstream */ 233 if (dev->error_state == pci_channel_io_frozen) { 234 dev->state_saved = true; 235 pci_restore_state(dev); 236 pcie_portdrv_restore_config(dev); 237 pci_enable_pcie_error_reporting(dev); 238 } 239 240 /* get true return value from &status */ 241 retval = device_for_each_child(&dev->dev, &status, slot_reset_iter); 242 243 return status; 244} 245 246static int resume_iter(struct device *device, void *data) 247{ 248 struct pcie_device *pcie_device; 249 struct pcie_port_service_driver *driver; 250 251 if (device->bus == &pcie_port_bus_type && device->driver) { 252 driver = to_service_driver(device->driver); 253 if (driver && 254 driver->err_handler && 255 driver->err_handler->resume) { 256 pcie_device = to_pcie_device(device); 257 258 /* Forward error message to service drivers */ 259 driver->err_handler->resume(pcie_device->port); 260 } 261 } 262 263 return 0; 264} 265 266static void pcie_portdrv_err_resume(struct pci_dev *dev) 267{ 268 int retval; 269 /* nothing to do with error value, if it ever happens */ 270 retval = device_for_each_child(&dev->dev, NULL, resume_iter); 271} 272 273/* 274 * LINUX Device Driver Model 275 */ 276static const struct pci_device_id port_pci_ids[] = { { 277 /* handle any PCI-Express port */ 278 PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0), 279 }, { /* end: all zeroes */ } 280}; 281MODULE_DEVICE_TABLE(pci, port_pci_ids); 282 283static struct pci_error_handlers pcie_portdrv_err_handler = { 284 .error_detected = pcie_portdrv_error_detected, 285 .mmio_enabled = pcie_portdrv_mmio_enabled, 286 .slot_reset = pcie_portdrv_slot_reset, 287 .resume = pcie_portdrv_err_resume, 288}; 289 290static struct pci_driver pcie_portdriver = { 291 .name = "pcieport", 292 .id_table = &port_pci_ids[0], 293 294 .probe = pcie_portdrv_probe, 295 .remove = pcie_portdrv_remove, 296 297 .err_handler = &pcie_portdrv_err_handler, 298 299 .driver.pm = PCIE_PORTDRV_PM_OPS, 300}; 301 302static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d) 303{ 304 pr_notice("%s detected: will not use MSI for PCIe PME signaling\n", 305 d->ident); 306 pcie_pme_disable_msi(); 307 return 0; 308} 309 310static struct dmi_system_id __initdata pcie_portdrv_dmi_table[] = { 311 /* 312 * Boxes that should not use MSI for PCIe PME signaling. 313 */ 314 { 315 .callback = dmi_pcie_pme_disable_msi, 316 .ident = "MSI Wind U-100", 317 .matches = { 318 DMI_MATCH(DMI_SYS_VENDOR, 319 "MICRO-STAR INTERNATIONAL CO., LTD"), 320 DMI_MATCH(DMI_PRODUCT_NAME, "U-100"), 321 }, 322 }, 323 {} 324}; 325 326static int __init pcie_portdrv_init(void) 327{ 328 int retval; 329 330 if (pcie_ports_disabled) { 331 pcie_no_aspm(); 332 return -EACCES; 333 } 334 335 dmi_check_system(pcie_portdrv_dmi_table); 336 337 retval = pcie_port_bus_register(); 338 if (retval) { 339 printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval); 340 goto out; 341 } 342 retval = pci_register_driver(&pcie_portdriver); 343 if (retval) 344 pcie_port_bus_unregister(); 345 out: 346 return retval; 347} 348 349module_init(pcie_portdrv_init); 350