Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+65 −74
Original line number Original line Diff line number Diff line
@@ -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 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;


	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) {
		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)
 		if (service_driver->suspend)
			service_driver->suspend(to_pcie_device(child), state);
 			service_driver->suspend(to_pcie_device(dev), state);
  	}
  	}
	return 0;
	return 0;
}
}


int pcie_port_device_resume(struct pci_dev *dev) 
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) {
		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)
		if (service_driver->resume)
			service_driver->resume(to_pcie_device(child));
			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
#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) {
		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)
			if (service_driver->remove)
				service_driver->remove(to_pcie_device(child));
				service_driver->remove(to_pcie_device(dev));
		}
		*(unsigned long*)data = (unsigned long)dev;
		return 1;
	}
	}
		interrupt_mode = (to_pcie_device(child))->interrupt_mode;
	return 0;
		put_device(child);
}
		device_unregister(child);

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);