diff options
Diffstat (limited to 'drivers/ieee1394/nodemgr.c')
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 120 |
1 files changed, 41 insertions, 79 deletions
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 04b62eca647b..2e6dc5990cef 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c | |||
@@ -12,8 +12,8 @@ | |||
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/completion.h> | ||
16 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/kthread.h> | ||
17 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
18 | #include <asm/atomic.h> | 18 | #include <asm/atomic.h> |
19 | 19 | ||
@@ -163,11 +163,7 @@ static DECLARE_MUTEX(nodemgr_serialize); | |||
163 | struct host_info { | 163 | struct host_info { |
164 | struct hpsb_host *host; | 164 | struct hpsb_host *host; |
165 | struct list_head list; | 165 | struct list_head list; |
166 | struct completion exited; | 166 | struct task_struct *thread; |
167 | struct semaphore reset_sem; | ||
168 | int pid; | ||
169 | char daemon_name[15]; | ||
170 | int kill_me; | ||
171 | }; | 167 | }; |
172 | 168 | ||
173 | 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); |
@@ -1477,9 +1473,8 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) | |||
1477 | /* 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 |
1478 | * 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 |
1479 | * 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 |
1480 | * 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 |
1481 | * so there's a bus scan pending which will do the clean up | 1477 | * do the clean up eventually. |
1482 | * eventually. | ||
1483 | * | 1478 | * |
1484 | * 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 |
1485 | * like overhead, but the driver-model core will only scan a | 1480 | * like overhead, but the driver-model core will only scan a |
@@ -1607,41 +1602,37 @@ static int nodemgr_host_thread(void *__hi) | |||
1607 | { | 1602 | { |
1608 | struct host_info *hi = (struct host_info *)__hi; | 1603 | struct host_info *hi = (struct host_info *)__hi; |
1609 | struct hpsb_host *host = hi->host; | 1604 | struct hpsb_host *host = hi->host; |
1610 | int reset_cycles = 0; | 1605 | unsigned int g, generation = get_hpsb_generation(host) - 1; |
1611 | 1606 | int i, reset_cycles = 0; | |
1612 | /* No userlevel access needed */ | ||
1613 | daemonize(hi->daemon_name); | ||
1614 | 1607 | ||
1615 | /* Setup our device-model entries */ | 1608 | /* Setup our device-model entries */ |
1616 | nodemgr_create_host_dev_files(host); | 1609 | nodemgr_create_host_dev_files(host); |
1617 | 1610 | ||
1618 | /* Sit and wait for a signal to probe the nodes on the bus. This | 1611 | for (;;) { |
1619 | * happens when we get a bus reset. */ | 1612 | /* Sleep until next bus reset */ |
1620 | while (1) { | 1613 | set_current_state(TASK_INTERRUPTIBLE); |
1621 | unsigned int generation = 0; | 1614 | if (get_hpsb_generation(host) == generation) |
1622 | int i; | 1615 | schedule(); |
1616 | __set_current_state(TASK_RUNNING); | ||
1617 | |||
1618 | /* Thread may have been woken up to freeze or to exit */ | ||
1619 | if (try_to_freeze()) | ||
1620 | continue; | ||
1621 | if (kthread_should_stop()) | ||
1622 | goto exit; | ||
1623 | 1623 | ||
1624 | if (down_interruptible(&hi->reset_sem) || | 1624 | if (down_interruptible(&nodemgr_serialize)) { |
1625 | down_interruptible(&nodemgr_serialize)) { | ||
1626 | if (try_to_freeze()) | 1625 | if (try_to_freeze()) |
1627 | continue; | 1626 | continue; |
1628 | printk("NodeMgr: received unexpected signal?!\n" ); | 1627 | goto exit; |
1629 | break; | ||
1630 | } | ||
1631 | |||
1632 | if (hi->kill_me) { | ||
1633 | up(&nodemgr_serialize); | ||
1634 | break; | ||
1635 | } | 1628 | } |
1636 | 1629 | ||
1637 | /* Pause for 1/4 second in 1/16 second intervals, | 1630 | /* Pause for 1/4 second in 1/16 second intervals, |
1638 | * to make sure things settle down. */ | 1631 | * to make sure things settle down. */ |
1632 | g = get_hpsb_generation(host); | ||
1639 | for (i = 0; i < 4 ; i++) { | 1633 | for (i = 0; i < 4 ; i++) { |
1640 | set_current_state(TASK_INTERRUPTIBLE); | 1634 | if (msleep_interruptible(63) || kthread_should_stop()) |
1641 | if (msleep_interruptible(63)) { | 1635 | goto unlock_exit; |
1642 | up(&nodemgr_serialize); | ||
1643 | goto caught_signal; | ||
1644 | } | ||
1645 | 1636 | ||
1646 | /* 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 |
1647 | * are valid. During the bus scan we will use this generation | 1638 | * are valid. During the bus scan we will use this generation |
@@ -1652,14 +1643,8 @@ static int nodemgr_host_thread(void *__hi) | |||
1652 | 1643 | ||
1653 | /* If we get a reset before we are done waiting, then | 1644 | /* If we get a reset before we are done waiting, then |
1654 | * start the the waiting over again */ | 1645 | * start the the waiting over again */ |
1655 | while (!down_trylock(&hi->reset_sem)) | 1646 | if (generation != g) |
1656 | i = 0; | 1647 | g = generation, i = 0; |
1657 | |||
1658 | /* Check the kill_me again */ | ||
1659 | if (hi->kill_me) { | ||
1660 | up(&nodemgr_serialize); | ||
1661 | goto caught_signal; | ||
1662 | } | ||
1663 | } | 1648 | } |
1664 | 1649 | ||
1665 | if (!nodemgr_check_irm_capability(host, reset_cycles) || | 1650 | if (!nodemgr_check_irm_capability(host, reset_cycles) || |
@@ -1685,11 +1670,11 @@ static int nodemgr_host_thread(void *__hi) | |||
1685 | 1670 | ||
1686 | up(&nodemgr_serialize); | 1671 | up(&nodemgr_serialize); |
1687 | } | 1672 | } |
1688 | 1673 | unlock_exit: | |
1689 | caught_signal: | 1674 | up(&nodemgr_serialize); |
1675 | exit: | ||
1690 | HPSB_VERBOSE("NodeMgr: Exiting thread"); | 1676 | HPSB_VERBOSE("NodeMgr: Exiting thread"); |
1691 | 1677 | return 0; | |
1692 | complete_and_exit(&hi->exited, 0); | ||
1693 | } | 1678 | } |
1694 | 1679 | ||
1695 | 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 *)) |
@@ -1749,41 +1734,27 @@ static void nodemgr_add_host(struct hpsb_host *host) | |||
1749 | struct host_info *hi; | 1734 | struct host_info *hi; |
1750 | 1735 | ||
1751 | hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi)); | 1736 | hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi)); |
1752 | |||
1753 | if (!hi) { | 1737 | if (!hi) { |
1754 | HPSB_ERR ("NodeMgr: out of memory in add host"); | 1738 | HPSB_ERR("NodeMgr: out of memory in add host"); |
1755 | return; | 1739 | return; |
1756 | } | 1740 | } |
1757 | |||
1758 | hi->host = host; | 1741 | hi->host = host; |
1759 | init_completion(&hi->exited); | 1742 | hi->thread = kthread_run(nodemgr_host_thread, hi, "knodemgrd_%d", |
1760 | sema_init(&hi->reset_sem, 0); | 1743 | host->id); |
1761 | 1744 | if (IS_ERR(hi->thread)) { | |
1762 | sprintf(hi->daemon_name, "knodemgrd_%d", host->id); | 1745 | HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id); |
1763 | |||
1764 | hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_KERNEL); | ||
1765 | |||
1766 | if (hi->pid < 0) { | ||
1767 | HPSB_ERR ("NodeMgr: failed to start %s thread for %s", | ||
1768 | hi->daemon_name, host->driver->name); | ||
1769 | hpsb_destroy_hostinfo(&nodemgr_highlevel, host); | 1746 | hpsb_destroy_hostinfo(&nodemgr_highlevel, host); |
1770 | return; | ||
1771 | } | 1747 | } |
1772 | |||
1773 | return; | ||
1774 | } | 1748 | } |
1775 | 1749 | ||
1776 | static void nodemgr_host_reset(struct hpsb_host *host) | 1750 | static void nodemgr_host_reset(struct hpsb_host *host) |
1777 | { | 1751 | { |
1778 | struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); | 1752 | struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); |
1779 | 1753 | ||
1780 | if (hi != NULL) { | 1754 | if (hi) { |
1781 | HPSB_VERBOSE("NodeMgr: Processing host reset for %s", hi->daemon_name); | 1755 | HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id); |
1782 | up(&hi->reset_sem); | 1756 | wake_up_process(hi->thread); |
1783 | } else | 1757 | } |
1784 | HPSB_ERR ("NodeMgr: could not process reset of unused host"); | ||
1785 | |||
1786 | return; | ||
1787 | } | 1758 | } |
1788 | 1759 | ||
1789 | static void nodemgr_remove_host(struct hpsb_host *host) | 1760 | static void nodemgr_remove_host(struct hpsb_host *host) |
@@ -1791,18 +1762,9 @@ static void nodemgr_remove_host(struct hpsb_host *host) | |||
1791 | struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); | 1762 | struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); |
1792 | 1763 | ||
1793 | if (hi) { | 1764 | if (hi) { |
1794 | if (hi->pid >= 0) { | 1765 | kthread_stop(hi->thread); |
1795 | hi->kill_me = 1; | 1766 | nodemgr_remove_host_dev(&host->device); |
1796 | mb(); | 1767 | } |
1797 | up(&hi->reset_sem); | ||
1798 | wait_for_completion(&hi->exited); | ||
1799 | nodemgr_remove_host_dev(&host->device); | ||
1800 | } | ||
1801 | } else | ||
1802 | HPSB_ERR("NodeMgr: host %s does not exist, cannot remove", | ||
1803 | host->driver->name); | ||
1804 | |||
1805 | return; | ||
1806 | } | 1768 | } |
1807 | 1769 | ||
1808 | static struct hpsb_highlevel nodemgr_highlevel = { | 1770 | static struct hpsb_highlevel nodemgr_highlevel = { |