diff options
Diffstat (limited to 'drivers/ieee1394/nodemgr.c')
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 173 |
1 files changed, 60 insertions, 113 deletions
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index d541b508a159..f8f6079cc48c 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c | |||
@@ -12,26 +12,23 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/list.h> | 13 | #include <linux/list.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/smp_lock.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kmod.h> | ||
18 | #include <linux/completion.h> | ||
19 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
20 | #include <linux/pci.h> | 16 | #include <linux/kthread.h> |
21 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
22 | #include <asm/atomic.h> | 18 | #include <asm/atomic.h> |
23 | 19 | ||
24 | #include "ieee1394_types.h" | 20 | #include "csr.h" |
21 | #include "highlevel.h" | ||
22 | #include "hosts.h" | ||
25 | #include "ieee1394.h" | 23 | #include "ieee1394.h" |
26 | #include "ieee1394_core.h" | 24 | #include "ieee1394_core.h" |
27 | #include "hosts.h" | 25 | #include "ieee1394_hotplug.h" |
26 | #include "ieee1394_types.h" | ||
28 | #include "ieee1394_transactions.h" | 27 | #include "ieee1394_transactions.h" |
29 | #include "highlevel.h" | ||
30 | #include "csr.h" | ||
31 | #include "nodemgr.h" | 28 | #include "nodemgr.h" |
32 | 29 | ||
33 | static int ignore_drivers; | 30 | static int ignore_drivers; |
34 | module_param(ignore_drivers, int, 0444); | 31 | module_param(ignore_drivers, int, S_IRUGO | S_IWUSR); |
35 | MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers."); | 32 | MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers."); |
36 | 33 | ||
37 | struct nodemgr_csr_info { | 34 | struct nodemgr_csr_info { |
@@ -71,7 +68,7 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr, | |||
71 | u8 i, *speed, old_speed, good_speed; | 68 | u8 i, *speed, old_speed, good_speed; |
72 | int ret; | 69 | int ret; |
73 | 70 | ||
74 | speed = ci->host->speed + NODEID_TO_NODE(ci->nodeid); | 71 | speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]); |
75 | old_speed = *speed; | 72 | old_speed = *speed; |
76 | good_speed = IEEE1394_SPEED_MAX + 1; | 73 | good_speed = IEEE1394_SPEED_MAX + 1; |
77 | 74 | ||
@@ -161,16 +158,12 @@ static struct csr1212_bus_ops nodemgr_csr_ops = { | |||
161 | * but now we are much simpler because of the LDM. | 158 | * but now we are much simpler because of the LDM. |
162 | */ | 159 | */ |
163 | 160 | ||
164 | static DECLARE_MUTEX(nodemgr_serialize); | 161 | static DEFINE_MUTEX(nodemgr_serialize); |
165 | 162 | ||
166 | struct host_info { | 163 | struct host_info { |
167 | struct hpsb_host *host; | 164 | struct hpsb_host *host; |
168 | struct list_head list; | 165 | struct list_head list; |
169 | struct completion exited; | 166 | struct task_struct *thread; |
170 | struct semaphore reset_sem; | ||
171 | int pid; | ||
172 | char daemon_name[15]; | ||
173 | int kill_me; | ||
174 | }; | 167 | }; |
175 | 168 | ||
176 | static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); | 169 | static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); |
@@ -408,26 +401,11 @@ static ssize_t fw_get_destroy_node(struct bus_type *bus, char *buf) | |||
408 | } | 401 | } |
409 | static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node); | 402 | static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node); |
410 | 403 | ||
411 | static int nodemgr_rescan_bus_thread(void *__unused) | ||
412 | { | ||
413 | /* No userlevel access needed */ | ||
414 | daemonize("kfwrescan"); | ||
415 | |||
416 | bus_rescan_devices(&ieee1394_bus_type); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | 404 | ||
421 | static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, size_t count) | 405 | static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, size_t count) |
422 | { | 406 | { |
423 | int state = simple_strtoul(buf, NULL, 10); | 407 | if (simple_strtoul(buf, NULL, 10) == 1) |
424 | 408 | bus_rescan_devices(&ieee1394_bus_type); | |
425 | /* Don't wait for this, or care about errors. Root could do | ||
426 | * something stupid and spawn this a lot of times, but that's | ||
427 | * root's fault. */ | ||
428 | if (state == 1) | ||
429 | kernel_thread(nodemgr_rescan_bus_thread, NULL, CLONE_KERNEL); | ||
430 | |||
431 | return count; | 409 | return count; |
432 | } | 410 | } |
433 | static ssize_t fw_get_rescan(struct bus_type *bus, char *buf) | 411 | static ssize_t fw_get_rescan(struct bus_type *bus, char *buf) |
@@ -1251,6 +1229,7 @@ static void nodemgr_node_scan_one(struct host_info *hi, | |||
1251 | octlet_t guid; | 1229 | octlet_t guid; |
1252 | struct csr1212_csr *csr; | 1230 | struct csr1212_csr *csr; |
1253 | struct nodemgr_csr_info *ci; | 1231 | struct nodemgr_csr_info *ci; |
1232 | u8 *speed; | ||
1254 | 1233 | ||
1255 | ci = kmalloc(sizeof(*ci), GFP_KERNEL); | 1234 | ci = kmalloc(sizeof(*ci), GFP_KERNEL); |
1256 | if (!ci) | 1235 | if (!ci) |
@@ -1259,8 +1238,12 @@ static void nodemgr_node_scan_one(struct host_info *hi, | |||
1259 | ci->host = host; | 1238 | ci->host = host; |
1260 | ci->nodeid = nodeid; | 1239 | ci->nodeid = nodeid; |
1261 | ci->generation = generation; | 1240 | ci->generation = generation; |
1262 | ci->speed_unverified = | 1241 | |
1263 | host->speed[NODEID_TO_NODE(nodeid)] > IEEE1394_SPEED_100; | 1242 | /* Prepare for speed probe which occurs when reading the ROM */ |
1243 | speed = &(host->speed[NODEID_TO_NODE(nodeid)]); | ||
1244 | if (*speed > host->csr.lnk_spd) | ||
1245 | *speed = host->csr.lnk_spd; | ||
1246 | ci->speed_unverified = *speed > IEEE1394_SPEED_100; | ||
1264 | 1247 | ||
1265 | /* We need to detect when the ConfigROM's generation has changed, | 1248 | /* We need to detect when the ConfigROM's generation has changed, |
1266 | * so we only update the node's info when it needs to be. */ | 1249 | * so we only update the node's info when it needs to be. */ |
@@ -1300,8 +1283,6 @@ static void nodemgr_node_scan_one(struct host_info *hi, | |||
1300 | nodemgr_create_node(guid, csr, hi, nodeid, generation); | 1283 | nodemgr_create_node(guid, csr, hi, nodeid, generation); |
1301 | else | 1284 | else |
1302 | nodemgr_update_node(ne, csr, hi, nodeid, generation); | 1285 | nodemgr_update_node(ne, csr, hi, nodeid, generation); |
1303 | |||
1304 | return; | ||
1305 | } | 1286 | } |
1306 | 1287 | ||
1307 | 1288 | ||
@@ -1492,9 +1473,8 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) | |||
1492 | /* If we had a bus reset while we were scanning the bus, it is | 1473 | /* If we had a bus reset while we were scanning the bus, it is |
1493 | * possible that we did not probe all nodes. In that case, we | 1474 | * possible that we did not probe all nodes. In that case, we |
1494 | * skip the clean up for now, since we could remove nodes that | 1475 | * skip the clean up for now, since we could remove nodes that |
1495 | * were still on the bus. The bus reset increased hi->reset_sem, | 1476 | * were still on the bus. Another bus scan is pending which will |
1496 | * so there's a bus scan pending which will do the clean up | 1477 | * do the clean up eventually. |
1497 | * eventually. | ||
1498 | * | 1478 | * |
1499 | * Now let's tell the bus to rescan our devices. This may seem | 1479 | * Now let's tell the bus to rescan our devices. This may seem |
1500 | * like overhead, but the driver-model core will only scan a | 1480 | * like overhead, but the driver-model core will only scan a |
@@ -1622,41 +1602,37 @@ static int nodemgr_host_thread(void *__hi) | |||
1622 | { | 1602 | { |
1623 | struct host_info *hi = (struct host_info *)__hi; | 1603 | struct host_info *hi = (struct host_info *)__hi; |
1624 | struct hpsb_host *host = hi->host; | 1604 | struct hpsb_host *host = hi->host; |
1625 | int reset_cycles = 0; | 1605 | unsigned int g, generation = get_hpsb_generation(host) - 1; |
1626 | 1606 | int i, reset_cycles = 0; | |
1627 | /* No userlevel access needed */ | ||
1628 | daemonize(hi->daemon_name); | ||
1629 | 1607 | ||
1630 | /* Setup our device-model entries */ | 1608 | /* Setup our device-model entries */ |
1631 | nodemgr_create_host_dev_files(host); | 1609 | nodemgr_create_host_dev_files(host); |
1632 | 1610 | ||
1633 | /* Sit and wait for a signal to probe the nodes on the bus. This | 1611 | for (;;) { |
1634 | * happens when we get a bus reset. */ | 1612 | /* Sleep until next bus reset */ |
1635 | while (1) { | 1613 | set_current_state(TASK_INTERRUPTIBLE); |
1636 | unsigned int generation = 0; | 1614 | if (get_hpsb_generation(host) == generation) |
1637 | int i; | 1615 | schedule(); |
1616 | __set_current_state(TASK_RUNNING); | ||
1638 | 1617 | ||
1639 | if (down_interruptible(&hi->reset_sem) || | 1618 | /* Thread may have been woken up to freeze or to exit */ |
1640 | down_interruptible(&nodemgr_serialize)) { | 1619 | if (try_to_freeze()) |
1620 | continue; | ||
1621 | if (kthread_should_stop()) | ||
1622 | goto exit; | ||
1623 | |||
1624 | if (mutex_lock_interruptible(&nodemgr_serialize)) { | ||
1641 | if (try_to_freeze()) | 1625 | if (try_to_freeze()) |
1642 | continue; | 1626 | continue; |
1643 | printk("NodeMgr: received unexpected signal?!\n" ); | 1627 | goto exit; |
1644 | break; | ||
1645 | } | ||
1646 | |||
1647 | if (hi->kill_me) { | ||
1648 | up(&nodemgr_serialize); | ||
1649 | break; | ||
1650 | } | 1628 | } |
1651 | 1629 | ||
1652 | /* Pause for 1/4 second in 1/16 second intervals, | 1630 | /* Pause for 1/4 second in 1/16 second intervals, |
1653 | * to make sure things settle down. */ | 1631 | * to make sure things settle down. */ |
1632 | g = get_hpsb_generation(host); | ||
1654 | for (i = 0; i < 4 ; i++) { | 1633 | for (i = 0; i < 4 ; i++) { |
1655 | set_current_state(TASK_INTERRUPTIBLE); | 1634 | if (msleep_interruptible(63) || kthread_should_stop()) |
1656 | if (msleep_interruptible(63)) { | 1635 | goto unlock_exit; |
1657 | up(&nodemgr_serialize); | ||
1658 | goto caught_signal; | ||
1659 | } | ||
1660 | 1636 | ||
1661 | /* Now get the generation in which the node ID's we collect | 1637 | /* Now get the generation in which the node ID's we collect |
1662 | * are valid. During the bus scan we will use this generation | 1638 | * are valid. During the bus scan we will use this generation |
@@ -1667,20 +1643,14 @@ static int nodemgr_host_thread(void *__hi) | |||
1667 | 1643 | ||
1668 | /* If we get a reset before we are done waiting, then | 1644 | /* If we get a reset before we are done waiting, then |
1669 | * start the the waiting over again */ | 1645 | * start the the waiting over again */ |
1670 | while (!down_trylock(&hi->reset_sem)) | 1646 | if (generation != g) |
1671 | i = 0; | 1647 | g = generation, i = 0; |
1672 | |||
1673 | /* Check the kill_me again */ | ||
1674 | if (hi->kill_me) { | ||
1675 | up(&nodemgr_serialize); | ||
1676 | goto caught_signal; | ||
1677 | } | ||
1678 | } | 1648 | } |
1679 | 1649 | ||
1680 | if (!nodemgr_check_irm_capability(host, reset_cycles) || | 1650 | if (!nodemgr_check_irm_capability(host, reset_cycles) || |
1681 | !nodemgr_do_irm_duties(host, reset_cycles)) { | 1651 | !nodemgr_do_irm_duties(host, reset_cycles)) { |
1682 | reset_cycles++; | 1652 | reset_cycles++; |
1683 | up(&nodemgr_serialize); | 1653 | mutex_unlock(&nodemgr_serialize); |
1684 | continue; | 1654 | continue; |
1685 | } | 1655 | } |
1686 | reset_cycles = 0; | 1656 | reset_cycles = 0; |
@@ -1698,13 +1668,13 @@ static int nodemgr_host_thread(void *__hi) | |||
1698 | /* Update some of our sysfs symlinks */ | 1668 | /* Update some of our sysfs symlinks */ |
1699 | nodemgr_update_host_dev_links(host); | 1669 | nodemgr_update_host_dev_links(host); |
1700 | 1670 | ||
1701 | up(&nodemgr_serialize); | 1671 | mutex_unlock(&nodemgr_serialize); |
1702 | } | 1672 | } |
1703 | 1673 | unlock_exit: | |
1704 | caught_signal: | 1674 | mutex_unlock(&nodemgr_serialize); |
1675 | exit: | ||
1705 | HPSB_VERBOSE("NodeMgr: Exiting thread"); | 1676 | HPSB_VERBOSE("NodeMgr: Exiting thread"); |
1706 | 1677 | return 0; | |
1707 | complete_and_exit(&hi->exited, 0); | ||
1708 | } | 1678 | } |
1709 | 1679 | ||
1710 | int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) | 1680 | int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) |
@@ -1764,41 +1734,27 @@ static void nodemgr_add_host(struct hpsb_host *host) | |||
1764 | struct host_info *hi; | 1734 | struct host_info *hi; |
1765 | 1735 | ||
1766 | hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi)); | 1736 | hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi)); |
1767 | |||
1768 | if (!hi) { | 1737 | if (!hi) { |
1769 | HPSB_ERR ("NodeMgr: out of memory in add host"); | 1738 | HPSB_ERR("NodeMgr: out of memory in add host"); |
1770 | return; | 1739 | return; |
1771 | } | 1740 | } |
1772 | |||
1773 | hi->host = host; | 1741 | hi->host = host; |
1774 | init_completion(&hi->exited); | 1742 | hi->thread = kthread_run(nodemgr_host_thread, hi, "knodemgrd_%d", |
1775 | sema_init(&hi->reset_sem, 0); | 1743 | host->id); |
1776 | 1744 | if (IS_ERR(hi->thread)) { | |
1777 | sprintf(hi->daemon_name, "knodemgrd_%d", host->id); | 1745 | HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id); |
1778 | |||
1779 | hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_KERNEL); | ||
1780 | |||
1781 | if (hi->pid < 0) { | ||
1782 | HPSB_ERR ("NodeMgr: failed to start %s thread for %s", | ||
1783 | hi->daemon_name, host->driver->name); | ||
1784 | hpsb_destroy_hostinfo(&nodemgr_highlevel, host); | 1746 | hpsb_destroy_hostinfo(&nodemgr_highlevel, host); |
1785 | return; | ||
1786 | } | 1747 | } |
1787 | |||
1788 | return; | ||
1789 | } | 1748 | } |
1790 | 1749 | ||
1791 | static void nodemgr_host_reset(struct hpsb_host *host) | 1750 | static void nodemgr_host_reset(struct hpsb_host *host) |
1792 | { | 1751 | { |
1793 | struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); | 1752 | struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); |
1794 | 1753 | ||
1795 | if (hi != NULL) { | 1754 | if (hi) { |
1796 | HPSB_VERBOSE("NodeMgr: Processing host reset for %s", hi->daemon_name); | 1755 | HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id); |
1797 | up(&hi->reset_sem); | 1756 | wake_up_process(hi->thread); |
1798 | } else | 1757 | } |
1799 | HPSB_ERR ("NodeMgr: could not process reset of unused host"); | ||
1800 | |||
1801 | return; | ||
1802 | } | 1758 | } |
1803 | 1759 | ||
1804 | static void nodemgr_remove_host(struct hpsb_host *host) | 1760 | static void nodemgr_remove_host(struct hpsb_host *host) |
@@ -1806,18 +1762,9 @@ static void nodemgr_remove_host(struct hpsb_host *host) | |||
1806 | struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); | 1762 | struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); |
1807 | 1763 | ||
1808 | if (hi) { | 1764 | if (hi) { |
1809 | if (hi->pid >= 0) { | 1765 | kthread_stop(hi->thread); |
1810 | hi->kill_me = 1; | 1766 | nodemgr_remove_host_dev(&host->device); |
1811 | mb(); | 1767 | } |
1812 | up(&hi->reset_sem); | ||
1813 | wait_for_completion(&hi->exited); | ||
1814 | nodemgr_remove_host_dev(&host->device); | ||
1815 | } | ||
1816 | } else | ||
1817 | HPSB_ERR("NodeMgr: host %s does not exist, cannot remove", | ||
1818 | host->driver->name); | ||
1819 | |||
1820 | return; | ||
1821 | } | 1768 | } |
1822 | 1769 | ||
1823 | static struct hpsb_highlevel nodemgr_highlevel = { | 1770 | static struct hpsb_highlevel nodemgr_highlevel = { |