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 printk(KERN_WARNING 95 "%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n", 96 __FUNCTION__, dev->vendor, dev->device); 97 } 98 if (pcie_port_device_register(dev)) { 99 pci_disable_device(dev); 100 return -ENOMEM; 101 } 102 103 pcie_portdrv_save_config(dev); 104 105 pci_enable_pcie_error_reporting(dev); 106 107 return 0; 108} 109 110static void pcie_portdrv_remove (struct pci_dev *dev) 111{ 112 pcie_port_device_remove(dev); 113 kfree(pci_get_drvdata(dev)); 114} 115 116static int error_detected_iter(struct device *device, void *data) 117{ 118 struct pcie_device *pcie_device; 119 struct pcie_port_service_driver *driver; 120 struct aer_broadcast_data *result_data; 121 pci_ers_result_t status; 122 123 result_data = (struct aer_broadcast_data *) data; 124 125 if (device->bus == &pcie_port_bus_type && device->driver) { 126 driver = to_service_driver(device->driver); 127 if (!driver || 128 !driver->err_handler || 129 !driver->err_handler->error_detected) 130 return 0; 131 132 pcie_device = to_pcie_device(device); 133 134 /* Forward error detected message to service drivers */ 135 status = driver->err_handler->error_detected( 136 pcie_device->port, 137 result_data->state); 138 result_data->result = 139 merge_result(result_data->result, status); 140 } 141 142 return 0; 143} 144 145static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, 146 enum pci_channel_state error) 147{ 148 struct aer_broadcast_data result_data = 149 {error, PCI_ERS_RESULT_CAN_RECOVER}; 150 int retval; 151 152 /* can not fail */ 153 retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter); 154 155 return result_data.result; 156} 157 158static int mmio_enabled_iter(struct device *device, void *data) 159{ 160 struct pcie_device *pcie_device; 161 struct pcie_port_service_driver *driver; 162 pci_ers_result_t status, *result; 163 164 result = (pci_ers_result_t *) data; 165 166 if (device->bus == &pcie_port_bus_type && device->driver) { 167 driver = to_service_driver(device->driver); 168 if (driver && 169 driver->err_handler && 170 driver->err_handler->mmio_enabled) { 171 pcie_device = to_pcie_device(device); 172 173 /* Forward error message to service drivers */ 174 status = driver->err_handler->mmio_enabled( 175 pcie_device->port); 176 *result = merge_result(*result, status); 177 } 178 } 179 180 return 0; 181} 182 183static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) 184{ 185 pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 186 int retval; 187 188 /* get true return value from &status */ 189 retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter); 190 return status; 191} 192 193static int slot_reset_iter(struct device *device, void *data) 194{ 195 struct pcie_device *pcie_device; 196 struct pcie_port_service_driver *driver; 197 pci_ers_result_t status, *result; 198 199 result = (pci_ers_result_t *) data; 200 201 if (device->bus == &pcie_port_bus_type && device->driver) { 202 driver = to_service_driver(device->driver); 203 if (driver && 204 driver->err_handler && 205 driver->err_handler->slot_reset) { 206 pcie_device = to_pcie_device(device); 207 208 /* Forward error message to service drivers */ 209 status = driver->err_handler->slot_reset( 210 pcie_device->port); 211 *result = merge_result(*result, status); 212 } 213 } 214 215 return 0; 216} 217 218static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) 219{ 220 pci_ers_result_t status; 221 int retval; 222 223 /* If fatal, restore cfg space for possible link reset at upstream */ 224 if (dev->error_state == pci_channel_io_frozen) { 225 pcie_portdrv_restore_config(dev); 226 pci_enable_pcie_error_reporting(dev); 227 } 228 229 /* get true return value from &status */ 230 retval = device_for_each_child(&dev->dev, &status, slot_reset_iter); 231 232 return status; 233} 234 235static int resume_iter(struct device *device, void *data) 236{ 237 struct pcie_device *pcie_device; 238 struct pcie_port_service_driver *driver; 239 240 if (device->bus == &pcie_port_bus_type && device->driver) { 241 driver = to_service_driver(device->driver); 242 if (driver && 243 driver->err_handler && 244 driver->err_handler->resume) { 245 pcie_device = to_pcie_device(device); 246 247 /* Forward error message to service drivers */ 248 driver->err_handler->resume(pcie_device->port); 249 } 250 } 251 252 return 0; 253} 254 255static void pcie_portdrv_err_resume(struct pci_dev *dev) 256{ 257 int retval; 258 /* nothing to do with error value, if it ever happens */ 259 retval = device_for_each_child(&dev->dev, NULL, resume_iter); 260} 261 262/* 263 * LINUX Device Driver Model 264 */ 265static const struct pci_device_id port_pci_ids[] = { { 266 /* handle any PCI-Express port */ 267 PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0), 268 }, { /* end: all zeroes */ } 269}; 270MODULE_DEVICE_TABLE(pci, port_pci_ids); 271 272static struct pci_error_handlers pcie_portdrv_err_handler = { 273 .error_detected = pcie_portdrv_error_detected, 274 .mmio_enabled = pcie_portdrv_mmio_enabled, 275 .slot_reset = pcie_portdrv_slot_reset, 276 .resume = pcie_portdrv_err_resume, 277}; 278 279static struct pci_driver pcie_portdriver = { 280 .name = (char *)device_name, 281 .id_table = &port_pci_ids[0], 282 283 .probe = pcie_portdrv_probe, 284 .remove = pcie_portdrv_remove, 285 286 .suspend = pcie_portdrv_suspend, 287 .resume = pcie_portdrv_resume, 288 289 .err_handler = &pcie_portdrv_err_handler, 290}; 291 292static int __init pcie_portdrv_init(void) 293{ 294 int retval; 295 296 retval = pcie_port_bus_register(); 297 if (retval) { 298 printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval); 299 goto out; 300 } 301 retval = pci_register_driver(&pcie_portdriver); 302 if (retval) 303 pcie_port_bus_unregister(); 304 out: 305 return retval; 306} 307 308static void __exit pcie_portdrv_exit(void) 309{ 310 pci_unregister_driver(&pcie_portdriver); 311 pcie_port_bus_unregister(); 312} 313 314module_init(pcie_portdrv_init); 315module_exit(pcie_portdrv_exit); 316