diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 314 |
1 files changed, 176 insertions, 138 deletions
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 90dc75be3418..511e4321c6b6 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c | |||
@@ -727,33 +727,31 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv) | |||
727 | 727 | ||
728 | static DEFINE_MUTEX(nodemgr_serialize_remove_uds); | 728 | static DEFINE_MUTEX(nodemgr_serialize_remove_uds); |
729 | 729 | ||
730 | static int __match_ne(struct device *dev, void *data) | ||
731 | { | ||
732 | struct unit_directory *ud; | ||
733 | struct node_entry *ne = (struct node_entry *)data; | ||
734 | |||
735 | ud = container_of(dev, struct unit_directory, unit_dev); | ||
736 | return ud->ne == ne; | ||
737 | } | ||
738 | |||
730 | static void nodemgr_remove_uds(struct node_entry *ne) | 739 | static void nodemgr_remove_uds(struct node_entry *ne) |
731 | { | 740 | { |
732 | struct device *dev; | 741 | struct device *dev; |
733 | struct unit_directory *tmp, *ud; | 742 | struct unit_directory *ud; |
734 | 743 | ||
735 | /* Iteration over nodemgr_ud_class.devices has to be protected by | 744 | /* Use class_find device to iterate the devices. Since this code |
736 | * nodemgr_ud_class.sem, but device_unregister() will eventually | 745 | * may be called from other contexts besides the knodemgrds, |
737 | * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time, | 746 | * protect it by nodemgr_serialize_remove_uds. |
738 | * release the semaphore, and then unregister the ud. Since this code | ||
739 | * may be called from other contexts besides the knodemgrds, protect the | ||
740 | * gap after release of the semaphore by nodemgr_serialize_remove_uds. | ||
741 | */ | 747 | */ |
742 | mutex_lock(&nodemgr_serialize_remove_uds); | 748 | mutex_lock(&nodemgr_serialize_remove_uds); |
743 | for (;;) { | 749 | for (;;) { |
744 | ud = NULL; | 750 | dev = class_find_device(&nodemgr_ud_class, ne, __match_ne); |
745 | down(&nodemgr_ud_class.sem); | 751 | if (!dev) |
746 | list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { | ||
747 | tmp = container_of(dev, struct unit_directory, | ||
748 | unit_dev); | ||
749 | if (tmp->ne == ne) { | ||
750 | ud = tmp; | ||
751 | break; | ||
752 | } | ||
753 | } | ||
754 | up(&nodemgr_ud_class.sem); | ||
755 | if (ud == NULL) | ||
756 | break; | 752 | break; |
753 | ud = container_of(dev, struct unit_directory, unit_dev); | ||
754 | put_device(dev); | ||
757 | device_unregister(&ud->unit_dev); | 755 | device_unregister(&ud->unit_dev); |
758 | device_unregister(&ud->device); | 756 | device_unregister(&ud->device); |
759 | } | 757 | } |
@@ -882,45 +880,66 @@ fail_alloc: | |||
882 | return NULL; | 880 | return NULL; |
883 | } | 881 | } |
884 | 882 | ||
883 | static int __match_ne_guid(struct device *dev, void *data) | ||
884 | { | ||
885 | struct node_entry *ne; | ||
886 | u64 *guid = (u64 *)data; | ||
887 | |||
888 | ne = container_of(dev, struct node_entry, node_dev); | ||
889 | return ne->guid == *guid; | ||
890 | } | ||
885 | 891 | ||
886 | static struct node_entry *find_entry_by_guid(u64 guid) | 892 | static struct node_entry *find_entry_by_guid(u64 guid) |
887 | { | 893 | { |
888 | struct device *dev; | 894 | struct device *dev; |
889 | struct node_entry *ne, *ret_ne = NULL; | 895 | struct node_entry *ne; |
890 | |||
891 | down(&nodemgr_ne_class.sem); | ||
892 | list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { | ||
893 | ne = container_of(dev, struct node_entry, node_dev); | ||
894 | 896 | ||
895 | if (ne->guid == guid) { | 897 | dev = class_find_device(&nodemgr_ne_class, &guid, __match_ne_guid); |
896 | ret_ne = ne; | 898 | if (!dev) |
897 | break; | 899 | return NULL; |
898 | } | 900 | ne = container_of(dev, struct node_entry, node_dev); |
899 | } | 901 | put_device(dev); |
900 | up(&nodemgr_ne_class.sem); | ||
901 | 902 | ||
902 | return ret_ne; | 903 | return ne; |
903 | } | 904 | } |
904 | 905 | ||
906 | struct match_nodeid_param { | ||
907 | struct hpsb_host *host; | ||
908 | nodeid_t nodeid; | ||
909 | }; | ||
910 | |||
911 | static int __match_ne_nodeid(struct device *dev, void *data) | ||
912 | { | ||
913 | int found = 0; | ||
914 | struct node_entry *ne; | ||
915 | struct match_nodeid_param *param = (struct match_nodeid_param *)data; | ||
916 | |||
917 | if (!dev) | ||
918 | goto ret; | ||
919 | ne = container_of(dev, struct node_entry, node_dev); | ||
920 | if (ne->host == param->host && ne->nodeid == param->nodeid) | ||
921 | found = 1; | ||
922 | ret: | ||
923 | return found; | ||
924 | } | ||
905 | 925 | ||
906 | static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, | 926 | static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, |
907 | nodeid_t nodeid) | 927 | nodeid_t nodeid) |
908 | { | 928 | { |
909 | struct device *dev; | 929 | struct device *dev; |
910 | struct node_entry *ne, *ret_ne = NULL; | 930 | struct node_entry *ne; |
931 | struct match_nodeid_param param; | ||
911 | 932 | ||
912 | down(&nodemgr_ne_class.sem); | 933 | param.host = host; |
913 | list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { | 934 | param.nodeid = nodeid; |
914 | ne = container_of(dev, struct node_entry, node_dev); | ||
915 | 935 | ||
916 | if (ne->host == host && ne->nodeid == nodeid) { | 936 | dev = class_find_device(&nodemgr_ne_class, ¶m, __match_ne_nodeid); |
917 | ret_ne = ne; | 937 | if (!dev) |
918 | break; | 938 | return NULL; |
919 | } | 939 | ne = container_of(dev, struct node_entry, node_dev); |
920 | } | 940 | put_device(dev); |
921 | up(&nodemgr_ne_class.sem); | ||
922 | 941 | ||
923 | return ret_ne; | 942 | return ne; |
924 | } | 943 | } |
925 | 944 | ||
926 | 945 | ||
@@ -1370,107 +1389,109 @@ static void nodemgr_node_scan(struct host_info *hi, int generation) | |||
1370 | } | 1389 | } |
1371 | } | 1390 | } |
1372 | 1391 | ||
1373 | 1392 | static int __nodemgr_driver_suspend(struct device *dev, void *data) | |
1374 | static void nodemgr_suspend_ne(struct node_entry *ne) | ||
1375 | { | 1393 | { |
1376 | struct device *dev; | ||
1377 | struct unit_directory *ud; | 1394 | struct unit_directory *ud; |
1378 | struct device_driver *drv; | 1395 | struct device_driver *drv; |
1396 | struct node_entry *ne = (struct node_entry *)data; | ||
1379 | int error; | 1397 | int error; |
1380 | 1398 | ||
1381 | HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", | 1399 | ud = container_of(dev, struct unit_directory, unit_dev); |
1382 | NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); | 1400 | if (ud->ne == ne) { |
1401 | drv = get_driver(ud->device.driver); | ||
1402 | if (drv) { | ||
1403 | error = 1; /* release if suspend is not implemented */ | ||
1404 | if (drv->suspend) { | ||
1405 | down(&ud->device.sem); | ||
1406 | error = drv->suspend(&ud->device, PMSG_SUSPEND); | ||
1407 | up(&ud->device.sem); | ||
1408 | } | ||
1409 | if (error) | ||
1410 | device_release_driver(&ud->device); | ||
1411 | put_driver(drv); | ||
1412 | } | ||
1413 | } | ||
1383 | 1414 | ||
1384 | ne->in_limbo = 1; | 1415 | return 0; |
1385 | WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); | 1416 | } |
1386 | 1417 | ||
1387 | down(&nodemgr_ud_class.sem); | 1418 | static int __nodemgr_driver_resume(struct device *dev, void *data) |
1388 | list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { | 1419 | { |
1389 | ud = container_of(dev, struct unit_directory, unit_dev); | 1420 | struct unit_directory *ud; |
1390 | if (ud->ne != ne) | 1421 | struct device_driver *drv; |
1391 | continue; | 1422 | struct node_entry *ne = (struct node_entry *)data; |
1392 | 1423 | ||
1424 | ud = container_of(dev, struct unit_directory, unit_dev); | ||
1425 | if (ud->ne == ne) { | ||
1393 | drv = get_driver(ud->device.driver); | 1426 | drv = get_driver(ud->device.driver); |
1394 | if (!drv) | 1427 | if (drv) { |
1395 | continue; | 1428 | if (drv->resume) { |
1396 | 1429 | down(&ud->device.sem); | |
1397 | error = 1; /* release if suspend is not implemented */ | 1430 | drv->resume(&ud->device); |
1398 | if (drv->suspend) { | 1431 | up(&ud->device.sem); |
1399 | down(&ud->device.sem); | 1432 | } |
1400 | error = drv->suspend(&ud->device, PMSG_SUSPEND); | 1433 | put_driver(drv); |
1401 | up(&ud->device.sem); | ||
1402 | } | 1434 | } |
1403 | if (error) | ||
1404 | device_release_driver(&ud->device); | ||
1405 | put_driver(drv); | ||
1406 | } | 1435 | } |
1407 | up(&nodemgr_ud_class.sem); | ||
1408 | } | ||
1409 | 1436 | ||
1437 | return 0; | ||
1438 | } | ||
1410 | 1439 | ||
1411 | static void nodemgr_resume_ne(struct node_entry *ne) | 1440 | static void nodemgr_suspend_ne(struct node_entry *ne) |
1412 | { | 1441 | { |
1413 | struct device *dev; | 1442 | HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", |
1414 | struct unit_directory *ud; | 1443 | NODE_BUS_ARGS(ne->host, ne->nodeid), |
1415 | struct device_driver *drv; | 1444 | (unsigned long long)ne->guid); |
1416 | 1445 | ||
1417 | ne->in_limbo = 0; | 1446 | ne->in_limbo = 1; |
1418 | device_remove_file(&ne->device, &dev_attr_ne_in_limbo); | 1447 | WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); |
1419 | 1448 | ||
1420 | down(&nodemgr_ud_class.sem); | 1449 | class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_suspend); |
1421 | list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { | 1450 | } |
1422 | ud = container_of(dev, struct unit_directory, unit_dev); | ||
1423 | if (ud->ne != ne) | ||
1424 | continue; | ||
1425 | 1451 | ||
1426 | drv = get_driver(ud->device.driver); | ||
1427 | if (!drv) | ||
1428 | continue; | ||
1429 | 1452 | ||
1430 | if (drv->resume) { | 1453 | static void nodemgr_resume_ne(struct node_entry *ne) |
1431 | down(&ud->device.sem); | 1454 | { |
1432 | drv->resume(&ud->device); | 1455 | ne->in_limbo = 0; |
1433 | up(&ud->device.sem); | 1456 | device_remove_file(&ne->device, &dev_attr_ne_in_limbo); |
1434 | } | ||
1435 | put_driver(drv); | ||
1436 | } | ||
1437 | up(&nodemgr_ud_class.sem); | ||
1438 | 1457 | ||
1458 | class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_resume); | ||
1439 | HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", | 1459 | HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", |
1440 | NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); | 1460 | NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); |
1441 | } | 1461 | } |
1442 | 1462 | ||
1443 | 1463 | static int __nodemgr_update_pdrv(struct device *dev, void *data) | |
1444 | static void nodemgr_update_pdrv(struct node_entry *ne) | ||
1445 | { | 1464 | { |
1446 | struct device *dev; | ||
1447 | struct unit_directory *ud; | 1465 | struct unit_directory *ud; |
1448 | struct device_driver *drv; | 1466 | struct device_driver *drv; |
1449 | struct hpsb_protocol_driver *pdrv; | 1467 | struct hpsb_protocol_driver *pdrv; |
1468 | struct node_entry *ne = (struct node_entry *)data; | ||
1450 | int error; | 1469 | int error; |
1451 | 1470 | ||
1452 | down(&nodemgr_ud_class.sem); | 1471 | ud = container_of(dev, struct unit_directory, unit_dev); |
1453 | list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { | 1472 | if (ud->ne == ne) { |
1454 | ud = container_of(dev, struct unit_directory, unit_dev); | ||
1455 | if (ud->ne != ne) | ||
1456 | continue; | ||
1457 | |||
1458 | drv = get_driver(ud->device.driver); | 1473 | drv = get_driver(ud->device.driver); |
1459 | if (!drv) | 1474 | if (drv) { |
1460 | continue; | 1475 | error = 0; |
1461 | 1476 | pdrv = container_of(drv, struct hpsb_protocol_driver, | |
1462 | error = 0; | 1477 | driver); |
1463 | pdrv = container_of(drv, struct hpsb_protocol_driver, driver); | 1478 | if (pdrv->update) { |
1464 | if (pdrv->update) { | 1479 | down(&ud->device.sem); |
1465 | down(&ud->device.sem); | 1480 | error = pdrv->update(ud); |
1466 | error = pdrv->update(ud); | 1481 | up(&ud->device.sem); |
1467 | up(&ud->device.sem); | 1482 | } |
1483 | if (error) | ||
1484 | device_release_driver(&ud->device); | ||
1485 | put_driver(drv); | ||
1468 | } | 1486 | } |
1469 | if (error) | ||
1470 | device_release_driver(&ud->device); | ||
1471 | put_driver(drv); | ||
1472 | } | 1487 | } |
1473 | up(&nodemgr_ud_class.sem); | 1488 | |
1489 | return 0; | ||
1490 | } | ||
1491 | |||
1492 | static void nodemgr_update_pdrv(struct node_entry *ne) | ||
1493 | { | ||
1494 | class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_update_pdrv); | ||
1474 | } | 1495 | } |
1475 | 1496 | ||
1476 | 1497 | ||
@@ -1529,13 +1550,31 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge | |||
1529 | put_device(dev); | 1550 | put_device(dev); |
1530 | } | 1551 | } |
1531 | 1552 | ||
1553 | struct probe_param { | ||
1554 | struct host_info *hi; | ||
1555 | int generation; | ||
1556 | }; | ||
1557 | |||
1558 | static int __nodemgr_node_probe(struct device *dev, void *data) | ||
1559 | { | ||
1560 | struct probe_param *param = (struct probe_param *)data; | ||
1561 | struct node_entry *ne; | ||
1562 | |||
1563 | ne = container_of(dev, struct node_entry, node_dev); | ||
1564 | if (!ne->needs_probe) | ||
1565 | nodemgr_probe_ne(param->hi, ne, param->generation); | ||
1566 | if (ne->needs_probe) | ||
1567 | nodemgr_probe_ne(param->hi, ne, param->generation); | ||
1568 | return 0; | ||
1569 | } | ||
1532 | 1570 | ||
1533 | static void nodemgr_node_probe(struct host_info *hi, int generation) | 1571 | static void nodemgr_node_probe(struct host_info *hi, int generation) |
1534 | { | 1572 | { |
1535 | struct hpsb_host *host = hi->host; | 1573 | struct hpsb_host *host = hi->host; |
1536 | struct device *dev; | 1574 | struct probe_param param; |
1537 | struct node_entry *ne; | ||
1538 | 1575 | ||
1576 | param.hi = hi; | ||
1577 | param.generation = generation; | ||
1539 | /* Do some processing of the nodes we've probed. This pulls them | 1578 | /* Do some processing of the nodes we've probed. This pulls them |
1540 | * into the sysfs layer if needed, and can result in processing of | 1579 | * into the sysfs layer if needed, and can result in processing of |
1541 | * unit-directories, or just updating the node and it's | 1580 | * unit-directories, or just updating the node and it's |
@@ -1545,19 +1584,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) | |||
1545 | * while probes are time-consuming. (Well, those probes need some | 1584 | * while probes are time-consuming. (Well, those probes need some |
1546 | * improvement...) */ | 1585 | * improvement...) */ |
1547 | 1586 | ||
1548 | down(&nodemgr_ne_class.sem); | 1587 | class_for_each_device(&nodemgr_ne_class, ¶m, __nodemgr_node_probe); |
1549 | list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { | ||
1550 | ne = container_of(dev, struct node_entry, node_dev); | ||
1551 | if (!ne->needs_probe) | ||
1552 | nodemgr_probe_ne(hi, ne, generation); | ||
1553 | } | ||
1554 | list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { | ||
1555 | ne = container_of(dev, struct node_entry, node_dev); | ||
1556 | if (ne->needs_probe) | ||
1557 | nodemgr_probe_ne(hi, ne, generation); | ||
1558 | } | ||
1559 | up(&nodemgr_ne_class.sem); | ||
1560 | |||
1561 | 1588 | ||
1562 | /* If we had a bus reset while we were scanning the bus, it is | 1589 | /* If we had a bus reset while we were scanning the bus, it is |
1563 | * possible that we did not probe all nodes. In that case, we | 1590 | * possible that we did not probe all nodes. In that case, we |
@@ -1757,6 +1784,22 @@ exit: | |||
1757 | return 0; | 1784 | return 0; |
1758 | } | 1785 | } |
1759 | 1786 | ||
1787 | struct host_iter_param { | ||
1788 | void *data; | ||
1789 | int (*cb)(struct hpsb_host *, void *); | ||
1790 | }; | ||
1791 | |||
1792 | static int __nodemgr_for_each_host(struct device *dev, void *data) | ||
1793 | { | ||
1794 | struct hpsb_host *host; | ||
1795 | struct host_iter_param *hip = (struct host_iter_param *)data; | ||
1796 | int error = 0; | ||
1797 | |||
1798 | host = container_of(dev, struct hpsb_host, host_dev); | ||
1799 | error = hip->cb(host, hip->data); | ||
1800 | |||
1801 | return error; | ||
1802 | } | ||
1760 | /** | 1803 | /** |
1761 | * nodemgr_for_each_host - call a function for each IEEE 1394 host | 1804 | * nodemgr_for_each_host - call a function for each IEEE 1394 host |
1762 | * @data: an address to supply to the callback | 1805 | * @data: an address to supply to the callback |
@@ -1771,18 +1814,13 @@ exit: | |||
1771 | */ | 1814 | */ |
1772 | int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) | 1815 | int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) |
1773 | { | 1816 | { |
1774 | struct device *dev; | 1817 | struct host_iter_param hip; |
1775 | struct hpsb_host *host; | 1818 | int error; |
1776 | int error = 0; | ||
1777 | |||
1778 | down(&hpsb_host_class.sem); | ||
1779 | list_for_each_entry(dev, &hpsb_host_class.devices, node) { | ||
1780 | host = container_of(dev, struct hpsb_host, host_dev); | ||
1781 | 1819 | ||
1782 | if ((error = cb(host, data))) | 1820 | hip.cb = cb; |
1783 | break; | 1821 | hip.data = data; |
1784 | } | 1822 | error = class_for_each_device(&hpsb_host_class, &hip, |
1785 | up(&hpsb_host_class.sem); | 1823 | __nodemgr_for_each_host); |
1786 | 1824 | ||
1787 | return error; | 1825 | return error; |
1788 | } | 1826 | } |