Commit d0e2b4a0 authored by long's avatar long Committed by Greg Kroah-Hartman

[PATCH] use device_for_each_child() to properly access child devices.

On Friday, March 25, 2005 8:47 PM Greg KH wrote:
>Here's a fix for pci express.  For some reason I don't think they are
>using the driver model properly here, but I could be wrong...

Thanks for making the changes. However, changes in functions:
void pcie_port_device_remove(struct pci_dev *dev) and
static int remove_iter(struct device *dev, void *data)
are not correct. Please use the patch, which is based on kernel
2.6.12-rc1, below for a fix for these.
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 64360322
...@@ -232,19 +232,16 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, ...@@ -232,19 +232,16 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
/* Initialize generic device interface */ /* Initialize generic device interface */
device = &dev->device; device = &dev->device;
memset(device, 0, sizeof(struct 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->bus = &pcie_port_bus_type;
device->driver = NULL; device->driver = NULL;
device->driver_data = NULL; device->driver_data = NULL;
device->release = release_pcie_device; /* callback to free pcie dev */ 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)); get_descriptor_id(port_type, service_type));
device->parent = &parent->dev; 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) int port_type, int service_type, int irq, int irq_mode)
{ {
struct pcie_device *device; struct pcie_device *device;
...@@ -270,9 +267,9 @@ int pcie_port_device_probe(struct pci_dev *dev) ...@@ -270,9 +267,9 @@ int pcie_port_device_probe(struct pci_dev *dev)
pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg); pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg);
type = (reg >> 4) & PORT_TYPE_MASK; type = (reg >> 4) & PORT_TYPE_MASK;
if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT || if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT ||
type == PCIE_SW_DOWNSTREAM_PORT ) type == PCIE_SW_DOWNSTREAM_PORT )
return 0; return 0;
return -ENODEV; return -ENODEV;
} }
...@@ -283,8 +280,8 @@ int pcie_port_device_register(struct pci_dev *dev) ...@@ -283,8 +280,8 @@ int pcie_port_device_register(struct pci_dev *dev)
u16 reg16; u16 reg16;
/* Get port type */ /* Get port type */
pci_read_config_word(dev, pci_read_config_word(dev,
pci_find_capability(dev, PCI_CAP_ID_EXP) + pci_find_capability(dev, PCI_CAP_ID_EXP) +
PCIE_CAPABILITIES_REG, &reg16); PCIE_CAPABILITIES_REG, &reg16);
type = (reg16 >> 4) & PORT_TYPE_MASK; type = (reg16 >> 4) & PORT_TYPE_MASK;
...@@ -299,11 +296,11 @@ int pcie_port_device_register(struct pci_dev *dev) ...@@ -299,11 +296,11 @@ int pcie_port_device_register(struct pci_dev *dev)
if (capabilities & (1 << i)) { if (capabilities & (1 << i)) {
child = alloc_pcie_device( child = alloc_pcie_device(
dev, /* parent */ dev, /* parent */
type, /* port type */ type, /* port type */
i, /* service type */ i, /* service type */
vectors[i], /* irq */ vectors[i], /* irq */
irq_mode /* interrupt mode */); irq_mode /* interrupt mode */);
if (child) { if (child) {
status = device_register(&child->device); status = device_register(&child->device);
if (status) { if (status) {
kfree(child); kfree(child);
...@@ -317,84 +314,78 @@ int pcie_port_device_register(struct pci_dev *dev) ...@@ -317,84 +314,78 @@ int pcie_port_device_register(struct pci_dev *dev)
} }
#ifdef CONFIG_PM #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; 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; int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
head = &parent->children; {
tmp = head->next; device_for_each_child(&dev->dev, (void *)state, suspend_iter);
while (head != tmp) { return 0;
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_resume(struct pci_dev *dev) static int resume_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; struct pcie_port_service_driver *service_driver;
parent = &dev->dev; if ((dev->bus == &pcie_port_bus_type) &&
head = &parent->children; (dev->driver)) {
tmp = head->next; service_driver = to_service_driver(dev->driver);
while (head != tmp) { if (service_driver->resume)
child = container_of(tmp, struct device, node); service_driver->resume(to_pcie_device(dev));
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));
} }
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 #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; struct pcie_port_service_driver *service_driver;
int interrupt_mode = PCIE_PORT_INTx_MODE;
parent = &dev->dev; if (dev->bus == &pcie_port_bus_type) {
head = &parent->children; if (dev->driver) {
tmp = head->next; service_driver = to_service_driver(dev->driver);
while (head != tmp) { if (service_driver->remove)
child = container_of(tmp, struct device, node); service_driver->remove(to_pcie_device(dev));
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));
} }
interrupt_mode = (to_pcie_device(child))->interrupt_mode; *(unsigned long*)data = (unsigned long)dev;
put_device(child); return 1;
device_unregister(child);
} }
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 */ /* Switch to INTx by default if MSI enabled */
if (interrupt_mode == PCIE_PORT_MSIX_MODE) if (interrupt_mode == PCIE_PORT_MSIX_MODE)
pci_disable_msix(dev); pci_disable_msix(dev);
...@@ -423,7 +414,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new) ...@@ -423,7 +414,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new)
new->driver.resume = pcie_port_resume_service; new->driver.resume = pcie_port_resume_service;
return driver_register(&new->driver); return driver_register(&new->driver);
} }
void pcie_port_service_unregister(struct pcie_port_service_driver *new) void pcie_port_service_unregister(struct pcie_port_service_driver *new)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment