diff options
Diffstat (limited to 'drivers/pci')
-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, | |||
232 | /* Initialize generic device interface */ | 232 | /* Initialize generic device interface */ |
233 | device = &dev->device; | 233 | device = &dev->device; |
234 | memset(device, 0, sizeof(struct device)); | 234 | memset(device, 0, sizeof(struct device)); |
235 | INIT_LIST_HEAD(&device->node); | ||
236 | INIT_LIST_HEAD(&device->children); | ||
237 | INIT_LIST_HEAD(&device->bus_list); | ||
238 | device->bus = &pcie_port_bus_type; | 235 | device->bus = &pcie_port_bus_type; |
239 | device->driver = NULL; | 236 | device->driver = NULL; |
240 | device->driver_data = NULL; | 237 | device->driver_data = NULL; |
241 | device->release = release_pcie_device; /* callback to free pcie dev */ | 238 | device->release = release_pcie_device; /* callback to free pcie dev */ |
242 | sprintf(&device->bus_id[0], "pcie%02x", | 239 | sprintf(&device->bus_id[0], "pcie%02x", |
243 | get_descriptor_id(port_type, service_type)); | 240 | get_descriptor_id(port_type, service_type)); |
244 | device->parent = &parent->dev; | 241 | device->parent = &parent->dev; |
245 | } | 242 | } |
246 | 243 | ||
247 | static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, | 244 | static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, |
248 | int port_type, int service_type, int irq, int irq_mode) | 245 | int port_type, int service_type, int irq, int irq_mode) |
249 | { | 246 | { |
250 | struct pcie_device *device; | 247 | struct pcie_device *device; |
@@ -270,9 +267,9 @@ int pcie_port_device_probe(struct pci_dev *dev) | |||
270 | pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®); | 267 | pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®); |
271 | type = (reg >> 4) & PORT_TYPE_MASK; | 268 | type = (reg >> 4) & PORT_TYPE_MASK; |
272 | if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT || | 269 | if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT || |
273 | type == PCIE_SW_DOWNSTREAM_PORT ) | 270 | type == PCIE_SW_DOWNSTREAM_PORT ) |
274 | return 0; | 271 | return 0; |
275 | 272 | ||
276 | return -ENODEV; | 273 | return -ENODEV; |
277 | } | 274 | } |
278 | 275 | ||
@@ -283,8 +280,8 @@ int pcie_port_device_register(struct pci_dev *dev) | |||
283 | u16 reg16; | 280 | u16 reg16; |
284 | 281 | ||
285 | /* Get port type */ | 282 | /* Get port type */ |
286 | pci_read_config_word(dev, | 283 | pci_read_config_word(dev, |
287 | pci_find_capability(dev, PCI_CAP_ID_EXP) + | 284 | pci_find_capability(dev, PCI_CAP_ID_EXP) + |
288 | PCIE_CAPABILITIES_REG, ®16); | 285 | PCIE_CAPABILITIES_REG, ®16); |
289 | type = (reg16 >> 4) & PORT_TYPE_MASK; | 286 | type = (reg16 >> 4) & PORT_TYPE_MASK; |
290 | 287 | ||
@@ -299,11 +296,11 @@ int pcie_port_device_register(struct pci_dev *dev) | |||
299 | if (capabilities & (1 << i)) { | 296 | if (capabilities & (1 << i)) { |
300 | child = alloc_pcie_device( | 297 | child = alloc_pcie_device( |
301 | dev, /* parent */ | 298 | dev, /* parent */ |
302 | type, /* port type */ | 299 | type, /* port type */ |
303 | i, /* service type */ | 300 | i, /* service type */ |
304 | vectors[i], /* irq */ | 301 | vectors[i], /* irq */ |
305 | irq_mode /* interrupt mode */); | 302 | irq_mode /* interrupt mode */); |
306 | if (child) { | 303 | if (child) { |
307 | status = device_register(&child->device); | 304 | status = device_register(&child->device); |
308 | if (status) { | 305 | if (status) { |
309 | kfree(child); | 306 | kfree(child); |
@@ -317,84 +314,78 @@ int pcie_port_device_register(struct pci_dev *dev) | |||
317 | } | 314 | } |
318 | 315 | ||
319 | #ifdef CONFIG_PM | 316 | #ifdef CONFIG_PM |
320 | int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) | 317 | static int suspend_iter(struct device *dev, void *data) |
321 | { | 318 | { |
322 | struct list_head *head, *tmp; | ||
323 | struct device *parent, *child; | ||
324 | struct device_driver *driver; | ||
325 | struct pcie_port_service_driver *service_driver; | 319 | struct pcie_port_service_driver *service_driver; |
320 | u32 state = (u32)data; | ||
321 | |||
322 | if ((dev->bus == &pcie_port_bus_type) && | ||
323 | (dev->driver)) { | ||
324 | service_driver = to_service_driver(dev->driver); | ||
325 | if (service_driver->suspend) | ||
326 | service_driver->suspend(to_pcie_device(dev), state); | ||
327 | } | ||
328 | return 0; | ||
329 | } | ||
326 | 330 | ||
327 | parent = &dev->dev; | 331 | int pcie_port_device_suspend(struct pci_dev *dev, u32 state) |
328 | head = &parent->children; | 332 | { |
329 | tmp = head->next; | 333 | device_for_each_child(&dev->dev, (void *)state, suspend_iter); |
330 | while (head != tmp) { | 334 | return 0; |
331 | child = container_of(tmp, struct device, node); | ||
332 | tmp = tmp->next; | ||
333 | if (child->bus != &pcie_port_bus_type) | ||
334 | continue; | ||
335 | driver = child->driver; | ||
336 | if (!driver) | ||
337 | continue; | ||
338 | service_driver = to_service_driver(driver); | ||
339 | if (service_driver->suspend) | ||
340 | service_driver->suspend(to_pcie_device(child), state); | ||
341 | } | ||
342 | return 0; | ||
343 | } | 335 | } |
344 | 336 | ||
345 | int pcie_port_device_resume(struct pci_dev *dev) | 337 | static int resume_iter(struct device *dev, void *data) |
346 | { | 338 | { |
347 | struct list_head *head, *tmp; | ||
348 | struct device *parent, *child; | ||
349 | struct device_driver *driver; | ||
350 | struct pcie_port_service_driver *service_driver; | 339 | struct pcie_port_service_driver *service_driver; |
351 | 340 | ||
352 | parent = &dev->dev; | 341 | if ((dev->bus == &pcie_port_bus_type) && |
353 | head = &parent->children; | 342 | (dev->driver)) { |
354 | tmp = head->next; | 343 | service_driver = to_service_driver(dev->driver); |
355 | while (head != tmp) { | 344 | if (service_driver->resume) |
356 | child = container_of(tmp, struct device, node); | 345 | service_driver->resume(to_pcie_device(dev)); |
357 | tmp = tmp->next; | ||
358 | if (child->bus != &pcie_port_bus_type) | ||
359 | continue; | ||
360 | driver = child->driver; | ||
361 | if (!driver) | ||
362 | continue; | ||
363 | service_driver = to_service_driver(driver); | ||
364 | if (service_driver->resume) | ||
365 | service_driver->resume(to_pcie_device(child)); | ||
366 | } | 346 | } |
367 | return 0; | 347 | return 0; |
348 | } | ||
368 | 349 | ||
350 | int pcie_port_device_resume(struct pci_dev *dev) | ||
351 | { | ||
352 | device_for_each_child(&dev->dev, NULL, resume_iter); | ||
353 | return 0; | ||
369 | } | 354 | } |
370 | #endif | 355 | #endif |
371 | 356 | ||
372 | void pcie_port_device_remove(struct pci_dev *dev) | 357 | static int remove_iter(struct device *dev, void *data) |
373 | { | 358 | { |
374 | struct list_head *head, *tmp; | ||
375 | struct device *parent, *child; | ||
376 | struct device_driver *driver; | ||
377 | struct pcie_port_service_driver *service_driver; | 359 | struct pcie_port_service_driver *service_driver; |
378 | int interrupt_mode = PCIE_PORT_INTx_MODE; | ||
379 | 360 | ||
380 | parent = &dev->dev; | 361 | if (dev->bus == &pcie_port_bus_type) { |
381 | head = &parent->children; | 362 | if (dev->driver) { |
382 | tmp = head->next; | 363 | service_driver = to_service_driver(dev->driver); |
383 | while (head != tmp) { | 364 | if (service_driver->remove) |
384 | child = container_of(tmp, struct device, node); | 365 | service_driver->remove(to_pcie_device(dev)); |
385 | tmp = tmp->next; | ||
386 | if (child->bus != &pcie_port_bus_type) | ||
387 | continue; | ||
388 | driver = child->driver; | ||
389 | if (driver) { | ||
390 | service_driver = to_service_driver(driver); | ||
391 | if (service_driver->remove) | ||
392 | service_driver->remove(to_pcie_device(child)); | ||
393 | } | 366 | } |
394 | interrupt_mode = (to_pcie_device(child))->interrupt_mode; | 367 | *(unsigned long*)data = (unsigned long)dev; |
395 | put_device(child); | 368 | return 1; |
396 | device_unregister(child); | ||
397 | } | 369 | } |
370 | return 0; | ||
371 | } | ||
372 | |||
373 | void pcie_port_device_remove(struct pci_dev *dev) | ||
374 | { | ||
375 | struct device *device; | ||
376 | unsigned long device_addr; | ||
377 | int interrupt_mode = PCIE_PORT_INTx_MODE; | ||
378 | int status; | ||
379 | |||
380 | do { | ||
381 | status = device_for_each_child(&dev->dev, &device_addr, remove_iter); | ||
382 | if (status) { | ||
383 | device = (struct device*)device_addr; | ||
384 | interrupt_mode = (to_pcie_device(device))->interrupt_mode; | ||
385 | put_device(device); | ||
386 | device_unregister(device); | ||
387 | } | ||
388 | } while (status); | ||
398 | /* Switch to INTx by default if MSI enabled */ | 389 | /* Switch to INTx by default if MSI enabled */ |
399 | if (interrupt_mode == PCIE_PORT_MSIX_MODE) | 390 | if (interrupt_mode == PCIE_PORT_MSIX_MODE) |
400 | pci_disable_msix(dev); | 391 | pci_disable_msix(dev); |
@@ -423,7 +414,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new) | |||
423 | new->driver.resume = pcie_port_resume_service; | 414 | new->driver.resume = pcie_port_resume_service; |
424 | 415 | ||
425 | return driver_register(&new->driver); | 416 | return driver_register(&new->driver); |
426 | } | 417 | } |
427 | 418 | ||
428 | void pcie_port_service_unregister(struct pcie_port_service_driver *new) | 419 | void pcie_port_service_unregister(struct pcie_port_service_driver *new) |
429 | { | 420 | { |