diff options
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 139 |
1 files changed, 65 insertions, 74 deletions
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 576285765e98..f5c5f10a3d2f 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -232,19 +232,16 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, /* Initialize generic device interface */ device = &dev->device; memset(device, 0, sizeof(struct device)); - INIT_LIST_HEAD(&device->node); - INIT_LIST_HEAD(&device->children); - INIT_LIST_HEAD(&device->bus_list); device->bus = &pcie_port_bus_type; device->driver = NULL; - device->driver_data = NULL; + device->driver_data = NULL; device->release = release_pcie_device; /* callback to free pcie dev */ - sprintf(&device->bus_id[0], "pcie%02x", + sprintf(&device->bus_id[0], "pcie%02x", get_descriptor_id(port_type, service_type)); device->parent = &parent->dev; } -static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, +static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, int port_type, int service_type, int irq, int irq_mode) { struct pcie_device *device; @@ -270,9 +267,9 @@ int pcie_port_device_probe(struct pci_dev *dev) pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®); type = (reg >> 4) & PORT_TYPE_MASK; if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT || - type == PCIE_SW_DOWNSTREAM_PORT ) + type == PCIE_SW_DOWNSTREAM_PORT ) return 0; - + return -ENODEV; } @@ -283,8 +280,8 @@ int pcie_port_device_register(struct pci_dev *dev) u16 reg16; /* Get port type */ - pci_read_config_word(dev, - pci_find_capability(dev, PCI_CAP_ID_EXP) + + pci_read_config_word(dev, + pci_find_capability(dev, PCI_CAP_ID_EXP) + PCIE_CAPABILITIES_REG, ®16); type = (reg16 >> 4) & PORT_TYPE_MASK; @@ -299,11 +296,11 @@ int pcie_port_device_register(struct pci_dev *dev) if (capabilities & (1 << i)) { child = alloc_pcie_device( dev, /* parent */ - type, /* port type */ + type, /* port type */ i, /* service type */ vectors[i], /* irq */ irq_mode /* interrupt mode */); - if (child) { + if (child) { status = device_register(&child->device); if (status) { kfree(child); @@ -317,84 +314,78 @@ int pcie_port_device_register(struct pci_dev *dev) } #ifdef CONFIG_PM -int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) +static int suspend_iter(struct device *dev, void *data) { - struct list_head *head, *tmp; - struct device *parent, *child; - struct device_driver *driver; struct pcie_port_service_driver *service_driver; + u32 state = (u32)data; + + if ((dev->bus == &pcie_port_bus_type) && + (dev->driver)) { + service_driver = to_service_driver(dev->driver); + if (service_driver->suspend) + service_driver->suspend(to_pcie_device(dev), state); + } + return 0; +} - parent = &dev->dev; - head = &parent->children; - tmp = head->next; - while (head != tmp) { - child = container_of(tmp, struct device, node); - tmp = tmp->next; - if (child->bus != &pcie_port_bus_type) - continue; - driver = child->driver; - if (!driver) - continue; - service_driver = to_service_driver(driver); - if (service_driver->suspend) - service_driver->suspend(to_pcie_device(child), state); - } - return 0; +int pcie_port_device_suspend(struct pci_dev *dev, u32 state) +{ + device_for_each_child(&dev->dev, (void *)state, suspend_iter); + return 0; } -int pcie_port_device_resume(struct pci_dev *dev) -{ - struct list_head *head, *tmp; - struct device *parent, *child; - struct device_driver *driver; +static int resume_iter(struct device *dev, void *data) +{ struct pcie_port_service_driver *service_driver; - parent = &dev->dev; - head = &parent->children; - tmp = head->next; - while (head != tmp) { - child = container_of(tmp, struct device, node); - tmp = tmp->next; - if (child->bus != &pcie_port_bus_type) - continue; - driver = child->driver; - if (!driver) - continue; - service_driver = to_service_driver(driver); - if (service_driver->resume) - service_driver->resume(to_pcie_device(child)); + if ((dev->bus == &pcie_port_bus_type) && + (dev->driver)) { + service_driver = to_service_driver(dev->driver); + if (service_driver->resume) + service_driver->resume(to_pcie_device(dev)); } - return 0; + return 0; +} +int pcie_port_device_resume(struct pci_dev *dev) +{ + device_for_each_child(&dev->dev, NULL, resume_iter); + return 0; } #endif -void pcie_port_device_remove(struct pci_dev *dev) +static int remove_iter(struct device *dev, void *data) { - struct list_head *head, *tmp; - struct device *parent, *child; - struct device_driver *driver; struct pcie_port_service_driver *service_driver; - int interrupt_mode = PCIE_PORT_INTx_MODE; - parent = &dev->dev; - head = &parent->children; - tmp = head->next; - while (head != tmp) { - child = container_of(tmp, struct device, node); - tmp = tmp->next; - if (child->bus != &pcie_port_bus_type) - continue; - driver = child->driver; - if (driver) { - service_driver = to_service_driver(driver); - if (service_driver->remove) - service_driver->remove(to_pcie_device(child)); + if (dev->bus == &pcie_port_bus_type) { + if (dev->driver) { + service_driver = to_service_driver(dev->driver); + if (service_driver->remove) + service_driver->remove(to_pcie_device(dev)); } - interrupt_mode = (to_pcie_device(child))->interrupt_mode; - put_device(child); - device_unregister(child); + *(unsigned long*)data = (unsigned long)dev; + return 1; } + return 0; +} + +void pcie_port_device_remove(struct pci_dev *dev) +{ + struct device *device; + unsigned long device_addr; + int interrupt_mode = PCIE_PORT_INTx_MODE; + int status; + + do { + status = device_for_each_child(&dev->dev, &device_addr, remove_iter); + if (status) { + device = (struct device*)device_addr; + interrupt_mode = (to_pcie_device(device))->interrupt_mode; + put_device(device); + device_unregister(device); + } + } while (status); /* Switch to INTx by default if MSI enabled */ if (interrupt_mode == PCIE_PORT_MSIX_MODE) pci_disable_msix(dev); @@ -423,7 +414,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new) new->driver.resume = pcie_port_resume_service; return driver_register(&new->driver); -} +} void pcie_port_service_unregister(struct pcie_port_service_driver *new) { |