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 v2.6.27 314 lines 7.4 kB view raw
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/slab.h> 16#include <linux/pcieport_if.h> 17#include <linux/aer.h> 18 19#include "portdrv.h" 20#include "aer/aerdrv.h" 21 22/* 23 * Version Information 24 */ 25#define DRIVER_VERSION "v1.0" 26#define DRIVER_AUTHOR "tom.l.nguyen@intel.com" 27#define DRIVER_DESC "PCIE Port Bus Driver" 28MODULE_AUTHOR(DRIVER_AUTHOR); 29MODULE_DESCRIPTION(DRIVER_DESC); 30MODULE_LICENSE("GPL"); 31 32/* global data */ 33static const char device_name[] = "pcieport-driver"; 34 35static int pcie_portdrv_save_config(struct pci_dev *dev) 36{ 37 return pci_save_state(dev); 38} 39 40static int pcie_portdrv_restore_config(struct pci_dev *dev) 41{ 42 int retval; 43 44 pci_restore_state(dev); 45 retval = pci_enable_device(dev); 46 if (retval) 47 return retval; 48 pci_set_master(dev); 49 return 0; 50} 51 52#ifdef CONFIG_PM 53static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) 54{ 55 int ret = pcie_port_device_suspend(dev, state); 56 57 if (!ret) 58 ret = pcie_portdrv_save_config(dev); 59 return ret; 60} 61 62static int pcie_portdrv_resume(struct pci_dev *dev) 63{ 64 pcie_portdrv_restore_config(dev); 65 return pcie_port_device_resume(dev); 66} 67#else 68#define pcie_portdrv_suspend NULL 69#define pcie_portdrv_resume NULL 70#endif 71 72/* 73 * pcie_portdrv_probe - Probe PCI-Express port devices 74 * @dev: PCI-Express port device being probed 75 * 76 * If detected invokes the pcie_port_device_register() method for 77 * this port device. 78 * 79 */ 80static int __devinit pcie_portdrv_probe (struct pci_dev *dev, 81 const struct pci_device_id *id ) 82{ 83 int status; 84 85 status = pcie_port_device_probe(dev); 86 if (status) 87 return status; 88 89 if (pci_enable_device(dev) < 0) 90 return -ENODEV; 91 92 pci_set_master(dev); 93 if (!dev->irq && dev->pin) { 94 dev_warn(&dev->dev, "device [%04x/%04x] has invalid IRQ; " 95 "check vendor BIOS\n", dev->vendor, dev->device); 96 } 97 if (pcie_port_device_register(dev)) { 98 pci_disable_device(dev); 99 return -ENOMEM; 100 } 101 102 pcie_portdrv_save_config(dev); 103 104 pci_enable_pcie_error_reporting(dev); 105 106 return 0; 107} 108 109static void pcie_portdrv_remove (struct pci_dev *dev) 110{ 111 pcie_port_device_remove(dev); 112 kfree(pci_get_drvdata(dev)); 113} 114 115static int error_detected_iter(struct device *device, void *data) 116{ 117 struct pcie_device *pcie_device; 118 struct pcie_port_service_driver *driver; 119 struct aer_broadcast_data *result_data; 120 pci_ers_result_t status; 121 122 result_data = (struct aer_broadcast_data *) data; 123 124 if (device->bus == &pcie_port_bus_type && device->driver) { 125 driver = to_service_driver(device->driver); 126 if (!driver || 127 !driver->err_handler || 128 !driver->err_handler->error_detected) 129 return 0; 130 131 pcie_device = to_pcie_device(device); 132 133 /* Forward error detected message to service drivers */ 134 status = driver->err_handler->error_detected( 135 pcie_device->port, 136 result_data->state); 137 result_data->result = 138 merge_result(result_data->result, status); 139 } 140 141 return 0; 142} 143 144static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, 145 enum pci_channel_state error) 146{ 147 struct aer_broadcast_data result_data = 148 {error, PCI_ERS_RESULT_CAN_RECOVER}; 149 int retval; 150 151 /* can not fail */ 152 retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter); 153 154 return result_data.result; 155} 156 157static int mmio_enabled_iter(struct device *device, void *data) 158{ 159 struct pcie_device *pcie_device; 160 struct pcie_port_service_driver *driver; 161 pci_ers_result_t status, *result; 162 163 result = (pci_ers_result_t *) data; 164 165 if (device->bus == &pcie_port_bus_type && device->driver) { 166 driver = to_service_driver(device->driver); 167 if (driver && 168 driver->err_handler && 169 driver->err_handler->mmio_enabled) { 170 pcie_device = to_pcie_device(device); 171 172 /* Forward error message to service drivers */ 173 status = driver->err_handler->mmio_enabled( 174 pcie_device->port); 175 *result = merge_result(*result, status); 176 } 177 } 178 179 return 0; 180} 181 182static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) 183{ 184 pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 185 int retval; 186 187 /* get true return value from &status */ 188 retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter); 189 return status; 190} 191 192static int slot_reset_iter(struct device *device, void *data) 193{ 194 struct pcie_device *pcie_device; 195 struct pcie_port_service_driver *driver; 196 pci_ers_result_t status, *result; 197 198 result = (pci_ers_result_t *) data; 199 200 if (device->bus == &pcie_port_bus_type && device->driver) { 201 driver = to_service_driver(device->driver); 202 if (driver && 203 driver->err_handler && 204 driver->err_handler->slot_reset) { 205 pcie_device = to_pcie_device(device); 206 207 /* Forward error message to service drivers */ 208 status = driver->err_handler->slot_reset( 209 pcie_device->port); 210 *result = merge_result(*result, status); 211 } 212 } 213 214 return 0; 215} 216 217static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) 218{ 219 pci_ers_result_t status = PCI_ERS_RESULT_NONE; 220 int retval; 221 222 /* If fatal, restore cfg space for possible link reset at upstream */ 223 if (dev->error_state == pci_channel_io_frozen) { 224 pcie_portdrv_restore_config(dev); 225 pci_enable_pcie_error_reporting(dev); 226 } 227 228 /* get true return value from &status */ 229 retval = device_for_each_child(&dev->dev, &status, slot_reset_iter); 230 231 return status; 232} 233 234static int resume_iter(struct device *device, void *data) 235{ 236 struct pcie_device *pcie_device; 237 struct pcie_port_service_driver *driver; 238 239 if (device->bus == &pcie_port_bus_type && device->driver) { 240 driver = to_service_driver(device->driver); 241 if (driver && 242 driver->err_handler && 243 driver->err_handler->resume) { 244 pcie_device = to_pcie_device(device); 245 246 /* Forward error message to service drivers */ 247 driver->err_handler->resume(pcie_device->port); 248 } 249 } 250 251 return 0; 252} 253 254static void pcie_portdrv_err_resume(struct pci_dev *dev) 255{ 256 int retval; 257 /* nothing to do with error value, if it ever happens */ 258 retval = device_for_each_child(&dev->dev, NULL, resume_iter); 259} 260 261/* 262 * LINUX Device Driver Model 263 */ 264static const struct pci_device_id port_pci_ids[] = { { 265 /* handle any PCI-Express port */ 266 PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0), 267 }, { /* end: all zeroes */ } 268}; 269MODULE_DEVICE_TABLE(pci, port_pci_ids); 270 271static struct pci_error_handlers pcie_portdrv_err_handler = { 272 .error_detected = pcie_portdrv_error_detected, 273 .mmio_enabled = pcie_portdrv_mmio_enabled, 274 .slot_reset = pcie_portdrv_slot_reset, 275 .resume = pcie_portdrv_err_resume, 276}; 277 278static struct pci_driver pcie_portdriver = { 279 .name = (char *)device_name, 280 .id_table = &port_pci_ids[0], 281 282 .probe = pcie_portdrv_probe, 283 .remove = pcie_portdrv_remove, 284 285 .suspend = pcie_portdrv_suspend, 286 .resume = pcie_portdrv_resume, 287 288 .err_handler = &pcie_portdrv_err_handler, 289}; 290 291static int __init pcie_portdrv_init(void) 292{ 293 int retval; 294 295 retval = pcie_port_bus_register(); 296 if (retval) { 297 printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval); 298 goto out; 299 } 300 retval = pci_register_driver(&pcie_portdriver); 301 if (retval) 302 pcie_port_bus_unregister(); 303 out: 304 return retval; 305} 306 307static void __exit pcie_portdrv_exit(void) 308{ 309 pci_unregister_driver(&pcie_portdriver); 310 pcie_port_bus_unregister(); 311} 312 313module_init(pcie_portdrv_init); 314module_exit(pcie_portdrv_exit);