static int error_detected_iter(struct device *device, void *data) { struct pcie_device *pcie_device; struct pcie_port_service_driver *driver; struct aer_broadcast_data *result_data; pci_ers_result_t status; result_data = (struct aer_broadcast_data *) data; if (device->bus == &pcie_port_bus_type && device->driver) { driver = to_service_driver(device->driver); if (!driver || !driver->err_handler || !driver->err_handler->error_detected) return 0; pcie_device = to_pcie_device(device); /* Forward error detected message to service drivers */ status = driver->err_handler->error_detected( pcie_device->port, result_data->state); result_data->result = merge_result(result_data->result, status); } return 0; }
static int find_aer_service_iter(struct device *device, void *data) { struct device_driver *driver; struct pcie_port_service_driver *service_driver; struct find_aer_service_data *result; result = (struct find_aer_service_data *) data; if (device->bus == &pcie_port_bus_type) { struct pcie_device *pcie = to_pcie_device(device); if (pcie->port->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) result->is_downstream = 1; driver = device->driver; if (driver) { service_driver = to_service_driver(driver); if (service_driver->service == PCIE_PORT_SERVICE_AER) { result->aer_driver = service_driver; return 1; } } } return 0; }
static pci_ers_result_t reset_link(struct pcie_device *aerdev, struct pci_dev *dev) { struct pci_dev *udev; pci_ers_result_t status; struct find_aer_service_data data; if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) udev = dev; else udev= dev->bus->self; data.is_downstream = 0; data.aer_driver = NULL; find_aer_service(udev, &data); /* * Use the aer driver of the error agent firstly. * If it hasn't the aer driver, use the root port's */ if (!data.aer_driver || !data.aer_driver->reset_link) { if (data.is_downstream && aerdev->device.driver && to_service_driver(aerdev->device.driver)->reset_link) { data.aer_driver = to_service_driver(aerdev->device.driver); } else { printk(KERN_DEBUG "No link-reset support to Device ID" "[%s]\n", dev->dev.bus_id); return PCI_ERS_RESULT_DISCONNECT; } } status = data.aer_driver->reset_link(udev); if (status != PCI_ERS_RESULT_RECOVERED) { printk(KERN_DEBUG "Link reset at upstream Device ID" "[%s] failed\n", udev->dev.bus_id); return PCI_ERS_RESULT_DISCONNECT; } return status; }
static pci_ers_result_t reset_link(struct pcie_device *aerdev, struct pci_dev *dev) { struct pci_dev *udev; pci_ers_result_t status; struct find_aer_service_data data; if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) udev = dev; else udev = dev->bus->self; data.is_downstream = 0; data.aer_driver = NULL; find_aer_service(udev, &data); if (!data.aer_driver || !data.aer_driver->reset_link) { if (data.is_downstream && aerdev->device.driver && to_service_driver(aerdev->device.driver)->reset_link) { data.aer_driver = to_service_driver(aerdev->device.driver); } else { dev_printk(KERN_DEBUG, &dev->dev, "no link-reset " "support\n"); return PCI_ERS_RESULT_DISCONNECT; } } status = data.aer_driver->reset_link(udev); if (status != PCI_ERS_RESULT_RECOVERED) { dev_printk(KERN_DEBUG, &dev->dev, "link reset at upstream " "device %s failed\n", pci_name(udev)); return PCI_ERS_RESULT_DISCONNECT; } return status; }
static int pcie_port_bus_resume(struct device *dev) { struct pcie_device *pciedev; struct pcie_port_service_driver *driver; if (!dev || !dev->driver) return 0; pciedev = to_pcie_device(dev); driver = to_service_driver(dev->driver); if (driver && driver->resume) driver->resume(pciedev); return 0; }
static int pcie_port_bus_suspend(struct device *dev, pm_message_t state) { struct pcie_device *pciedev; struct pcie_port_service_driver *driver; if (!dev || !dev->driver) return 0; pciedev = to_pcie_device(dev); driver = to_service_driver(dev->driver); if (driver && driver->suspend) driver->suspend(pciedev, state); return 0; }
static int find_aer_service_iter(struct device *device, void *data) { struct pcie_port_service_driver *service_driver, **drv; drv = (struct pcie_port_service_driver **) data; if (device->bus == &pcie_port_bus_type && device->driver) { service_driver = to_service_driver(device->driver); if (service_driver->service == PCIE_PORT_SERVICE_AER) { *drv = service_driver; return 1; } } return 0; }
static int resume_iter(struct device *device, void *data) { struct pcie_device *pcie_device; struct pcie_port_service_driver *driver; if (device->bus == &pcie_port_bus_type && device->driver) { driver = to_service_driver(device->driver); if (driver && driver->err_handler && driver->err_handler->resume) { pcie_device = to_pcie_device(device); /* Forward error message to service drivers */ driver->err_handler->resume(pcie_device->port); } } return 0; }
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) { struct pcie_device *pciedev; struct pcie_port_service_driver *driver; if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) return 0; pciedev = to_pcie_device(dev); driver = to_service_driver(drv); if (driver->service != pciedev->service) return 0; if ((driver->port_type != PCIE_ANY_PORT) && (driver->port_type != pci_pcie_type(pciedev->port))) return 0; return 1; }
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) { struct pcie_device *pciedev; struct pcie_port_service_driver *driver; if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) return 0; pciedev = to_pcie_device(dev); driver = to_service_driver(drv); if ( (driver->id_table->vendor != PCI_ANY_ID && driver->id_table->vendor != pciedev->id.vendor) || (driver->id_table->device != PCI_ANY_ID && driver->id_table->device != pciedev->id.device) || (driver->id_table->port_type != PCIE_ANY_PORT && driver->id_table->port_type != pciedev->id.port_type) || driver->id_table->service_type != pciedev->id.service_type ) return 0; return 1; }
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) { struct pcie_device *pciedev; struct pcie_port_data *port_data; struct pcie_port_service_driver *driver; if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) return 0; pciedev = to_pcie_device(dev); driver = to_service_driver(drv); if (driver->service != pciedev->service) return 0; port_data = pci_get_drvdata(pciedev->port); if (driver->port_type != PCIE_ANY_PORT && driver->port_type != port_data->port_type) return 0; return 1; }
static int slot_reset_iter(struct device *device, void *data) { struct pcie_device *pcie_device; struct pcie_port_service_driver *driver; pci_ers_result_t status, *result; result = (pci_ers_result_t *) data; if (device->bus == &pcie_port_bus_type && device->driver) { driver = to_service_driver(device->driver); if (driver && driver->err_handler && driver->err_handler->slot_reset) { pcie_device = to_pcie_device(device); /* Forward error message to service drivers */ status = driver->err_handler->slot_reset( pcie_device->port); *result = merge_result(*result, status); } } return 0; }
static int mmio_enabled_iter(struct device *device, void *data) { struct pcie_device *pcie_device; struct pcie_port_service_driver *driver; pci_ers_result_t status, *result; result = (pci_ers_result_t *) data; if (device->bus == &pcie_port_bus_type && device->driver) { driver = to_service_driver(device->driver); if (driver && driver->err_handler && driver->err_handler->mmio_enabled) { pcie_device = to_pcie_device(device); status = driver->err_handler->mmio_enabled( pcie_device->port); *result = merge_result(*result, status); } } return 0; }