[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: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
64360322ab
commit
d0e2b4a0a9
1 changed files with 65 additions and 74 deletions
|
@ -232,9 +232,6 @@ 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;
|
||||||
|
@ -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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
|
||||||
|
{
|
||||||
|
device_for_each_child(&dev->dev, (void *)state, suspend_iter);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->suspend)
|
|
||||||
service_driver->suspend(to_pcie_device(child), state);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcie_port_device_resume(struct pci_dev *dev)
|
int pcie_port_device_resume(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct list_head *head, *tmp;
|
device_for_each_child(&dev->dev, NULL, resume_iter);
|
||||||
struct device *parent, *child;
|
|
||||||
struct device_driver *driver;
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int remove_iter(struct device *dev, void *data)
|
||||||
|
{
|
||||||
|
struct pcie_port_service_driver *service_driver;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
*(unsigned long*)data = (unsigned long)dev;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void pcie_port_device_remove(struct pci_dev *dev)
|
void pcie_port_device_remove(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct list_head *head, *tmp;
|
struct device *device;
|
||||||
struct device *parent, *child;
|
unsigned long device_addr;
|
||||||
struct device_driver *driver;
|
|
||||||
struct pcie_port_service_driver *service_driver;
|
|
||||||
int interrupt_mode = PCIE_PORT_INTx_MODE;
|
int interrupt_mode = PCIE_PORT_INTx_MODE;
|
||||||
|
int status;
|
||||||
|
|
||||||
parent = &dev->dev;
|
do {
|
||||||
head = &parent->children;
|
status = device_for_each_child(&dev->dev, &device_addr, remove_iter);
|
||||||
tmp = head->next;
|
if (status) {
|
||||||
while (head != tmp) {
|
device = (struct device*)device_addr;
|
||||||
child = container_of(tmp, struct device, node);
|
interrupt_mode = (to_pcie_device(device))->interrupt_mode;
|
||||||
tmp = tmp->next;
|
put_device(device);
|
||||||
if (child->bus != &pcie_port_bus_type)
|
device_unregister(device);
|
||||||
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;
|
} while (status);
|
||||||
put_device(child);
|
|
||||||
device_unregister(child);
|
|
||||||
}
|
|
||||||
/* 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);
|
||||||
|
|
Loading…
Reference in a new issue