diff options
| -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 | } |
