diff options
author | Alexandre Bounine <alexandre.bounine@idt.com> | 2013-07-03 18:08:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 19:08:04 -0400 |
commit | 9edbc30b434f56258d03faac5daf37a555384db3 (patch) | |
tree | d6454e8d28a6177d31f91bf081bb0602b8c73056 /drivers/rapidio | |
parent | e6161d64263ee7a903acdde1a8ab7d4221d5512f (diff) |
rapidio: update enumerator registration mechanism
Update enumeration/discovery method registration mechanism to allow
loading enumeration/discovery methods before all mports are registered.
Existing statically linked RapidIO subsystem expects that all available
RapidIO mport devices are initialized and registered before the
enumeration/discovery method is registered. Switching to loadable mport
device drivers creates situation when mport device driver can be loaded
after enumeration/discovery method is attached (e.g., loadable mport
driver in a system with statically linked RapidIO core and enumerator).
This also will happen in a system with hot-pluggable RapidIO controllers.
To remove the dependency on the initialization/registration order this
patch introduces enumeration/discovery registration mechanism that
supports arbitrary registration order of mports and enumerator/discovery
methods.
The following registration rules are implemented:
- only one enumeration/discovery method can be registered for given mport ID
(including RIO_MPORT_ANY);
- when new enumeration/discovery methods tries to attach to the registered mport
device, method with matching mport ID will replace a default method previously
registered for given mport (if any);
- enumeration/discovery method with target ID=RIO_MPORT_ANY will be attached
only to mports that do not have another enumerator attached to them;
- when new mport device is registered with RapidIO subsystem, registration
routine searches for the enumeration/discovery method with the best matching
mport ID;
Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Li Yang <leoli@freescale.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Andre van Herk <andre.van.herk@Prodrive.nl>
Cc: Micha Nelissen <micha.nelissen@Prodrive.nl>
Cc: Stef van Os <stef.van.os@Prodrive.nl>
Cc: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rapidio')
-rw-r--r-- | drivers/rapidio/rio-scan.c | 1 | ||||
-rw-r--r-- | drivers/rapidio/rio-sysfs.c | 17 | ||||
-rw-r--r-- | drivers/rapidio/rio.c | 176 | ||||
-rw-r--r-- | drivers/rapidio/rio.h | 3 |
4 files changed, 149 insertions, 48 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 913950212605..ab837fdb2383 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c | |||
@@ -1162,6 +1162,7 @@ bail: | |||
1162 | } | 1162 | } |
1163 | 1163 | ||
1164 | static struct rio_scan rio_scan_ops = { | 1164 | static struct rio_scan rio_scan_ops = { |
1165 | .owner = THIS_MODULE, | ||
1165 | .enumerate = rio_enum_mport, | 1166 | .enumerate = rio_enum_mport, |
1166 | .discover = rio_disc_mport, | 1167 | .discover = rio_disc_mport, |
1167 | }; | 1168 | }; |
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 864e52f193e1..0c4473e54f86 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c | |||
@@ -286,7 +286,6 @@ static ssize_t bus_scan_store(struct bus_type *bus, const char *buf, | |||
286 | size_t count) | 286 | size_t count) |
287 | { | 287 | { |
288 | long val; | 288 | long val; |
289 | struct rio_mport *port = NULL; | ||
290 | int rc; | 289 | int rc; |
291 | 290 | ||
292 | if (kstrtol(buf, 0, &val) < 0) | 291 | if (kstrtol(buf, 0, &val) < 0) |
@@ -300,21 +299,7 @@ static ssize_t bus_scan_store(struct bus_type *bus, const char *buf, | |||
300 | if (val < 0 || val >= RIO_MAX_MPORTS) | 299 | if (val < 0 || val >= RIO_MAX_MPORTS) |
301 | return -EINVAL; | 300 | return -EINVAL; |
302 | 301 | ||
303 | port = rio_find_mport((int)val); | 302 | rc = rio_mport_scan((int)val); |
304 | |||
305 | if (!port) { | ||
306 | pr_debug("RIO: %s: mport_%d not available\n", | ||
307 | __func__, (int)val); | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | |||
311 | if (!port->nscan) | ||
312 | return -EINVAL; | ||
313 | |||
314 | if (port->host_deviceid >= 0) | ||
315 | rc = port->nscan->enumerate(port, 0); | ||
316 | else | ||
317 | rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT); | ||
318 | exit: | 303 | exit: |
319 | if (!rc) | 304 | if (!rc) |
320 | rc = count; | 305 | rc = count; |
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index b17d5218005e..5eb727cd0652 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
@@ -34,6 +34,7 @@ static LIST_HEAD(rio_devices); | |||
34 | static DEFINE_SPINLOCK(rio_global_list_lock); | 34 | static DEFINE_SPINLOCK(rio_global_list_lock); |
35 | 35 | ||
36 | static LIST_HEAD(rio_mports); | 36 | static LIST_HEAD(rio_mports); |
37 | static LIST_HEAD(rio_scans); | ||
37 | static DEFINE_MUTEX(rio_mport_list_lock); | 38 | static DEFINE_MUTEX(rio_mport_list_lock); |
38 | static unsigned char next_portid; | 39 | static unsigned char next_portid; |
39 | static DEFINE_SPINLOCK(rio_mmap_lock); | 40 | static DEFINE_SPINLOCK(rio_mmap_lock); |
@@ -1602,34 +1603,73 @@ found: | |||
1602 | * rio_register_scan - enumeration/discovery method registration interface | 1603 | * rio_register_scan - enumeration/discovery method registration interface |
1603 | * @mport_id: mport device ID for which fabric scan routine has to be set | 1604 | * @mport_id: mport device ID for which fabric scan routine has to be set |
1604 | * (RIO_MPORT_ANY = set for all available mports) | 1605 | * (RIO_MPORT_ANY = set for all available mports) |
1605 | * @scan_ops: enumeration/discovery control structure | 1606 | * @scan_ops: enumeration/discovery operations structure |
1607 | * | ||
1608 | * Registers enumeration/discovery operations with RapidIO subsystem and | ||
1609 | * attaches it to the specified mport device (or all available mports | ||
1610 | * if RIO_MPORT_ANY is specified). | ||
1606 | * | 1611 | * |
1607 | * Assigns enumeration or discovery method to the specified mport device (or all | ||
1608 | * available mports if RIO_MPORT_ANY is specified). | ||
1609 | * Returns error if the mport already has an enumerator attached to it. | 1612 | * Returns error if the mport already has an enumerator attached to it. |
1610 | * In case of RIO_MPORT_ANY ignores ports with valid scan routines and returns | 1613 | * In case of RIO_MPORT_ANY skips mports with valid scan routines (no error). |
1611 | * an error if was unable to find at least one available mport. | ||
1612 | */ | 1614 | */ |
1613 | int rio_register_scan(int mport_id, struct rio_scan *scan_ops) | 1615 | int rio_register_scan(int mport_id, struct rio_scan *scan_ops) |
1614 | { | 1616 | { |
1615 | struct rio_mport *port; | 1617 | struct rio_mport *port; |
1616 | int rc = -EBUSY; | 1618 | struct rio_scan_node *scan; |
1619 | int rc = 0; | ||
1617 | 1620 | ||
1618 | mutex_lock(&rio_mport_list_lock); | 1621 | pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id); |
1619 | list_for_each_entry(port, &rio_mports, node) { | ||
1620 | if (port->id == mport_id || mport_id == RIO_MPORT_ANY) { | ||
1621 | if (port->nscan && mport_id == RIO_MPORT_ANY) | ||
1622 | continue; | ||
1623 | else if (port->nscan) | ||
1624 | break; | ||
1625 | 1622 | ||
1626 | port->nscan = scan_ops; | 1623 | if ((mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) || |
1627 | rc = 0; | 1624 | !scan_ops) |
1625 | return -EINVAL; | ||
1628 | 1626 | ||
1629 | if (mport_id != RIO_MPORT_ANY) | 1627 | mutex_lock(&rio_mport_list_lock); |
1630 | break; | 1628 | |
1629 | /* | ||
1630 | * Check if there is another enumerator already registered for | ||
1631 | * the same mport ID (including RIO_MPORT_ANY). Multiple enumerators | ||
1632 | * for the same mport ID are not supported. | ||
1633 | */ | ||
1634 | list_for_each_entry(scan, &rio_scans, node) { | ||
1635 | if (scan->mport_id == mport_id) { | ||
1636 | rc = -EBUSY; | ||
1637 | goto err_out; | ||
1631 | } | 1638 | } |
1632 | } | 1639 | } |
1640 | |||
1641 | /* | ||
1642 | * Allocate and initialize new scan registration node. | ||
1643 | */ | ||
1644 | scan = kzalloc(sizeof(*scan), GFP_KERNEL); | ||
1645 | if (!scan) { | ||
1646 | rc = -ENOMEM; | ||
1647 | goto err_out; | ||
1648 | } | ||
1649 | |||
1650 | scan->mport_id = mport_id; | ||
1651 | scan->ops = scan_ops; | ||
1652 | |||
1653 | /* | ||
1654 | * Traverse the list of registered mports to attach this new scan. | ||
1655 | * | ||
1656 | * The new scan with matching mport ID overrides any previously attached | ||
1657 | * scan assuming that old scan (if any) is the default one (based on the | ||
1658 | * enumerator registration check above). | ||
1659 | * If the new scan is the global one, it will be attached only to mports | ||
1660 | * that do not have their own individual operations already attached. | ||
1661 | */ | ||
1662 | list_for_each_entry(port, &rio_mports, node) { | ||
1663 | if (port->id == mport_id) { | ||
1664 | port->nscan = scan_ops; | ||
1665 | break; | ||
1666 | } else if (mport_id == RIO_MPORT_ANY && !port->nscan) | ||
1667 | port->nscan = scan_ops; | ||
1668 | } | ||
1669 | |||
1670 | list_add_tail(&scan->node, &rio_scans); | ||
1671 | |||
1672 | err_out: | ||
1633 | mutex_unlock(&rio_mport_list_lock); | 1673 | mutex_unlock(&rio_mport_list_lock); |
1634 | 1674 | ||
1635 | return rc; | 1675 | return rc; |
@@ -1639,30 +1679,81 @@ EXPORT_SYMBOL_GPL(rio_register_scan); | |||
1639 | /** | 1679 | /** |
1640 | * rio_unregister_scan - removes enumeration/discovery method from mport | 1680 | * rio_unregister_scan - removes enumeration/discovery method from mport |
1641 | * @mport_id: mport device ID for which fabric scan routine has to be | 1681 | * @mport_id: mport device ID for which fabric scan routine has to be |
1642 | * unregistered (RIO_MPORT_ANY = set for all available mports) | 1682 | * unregistered (RIO_MPORT_ANY = apply to all mports that use |
1683 | * the specified scan_ops) | ||
1684 | * @scan_ops: enumeration/discovery operations structure | ||
1643 | * | 1685 | * |
1644 | * Removes enumeration or discovery method assigned to the specified mport | 1686 | * Removes enumeration or discovery method assigned to the specified mport |
1645 | * device (or all available mports if RIO_MPORT_ANY is specified). | 1687 | * device. If RIO_MPORT_ANY is specified, removes the specified operations from |
1688 | * all mports that have them attached. | ||
1646 | */ | 1689 | */ |
1647 | int rio_unregister_scan(int mport_id) | 1690 | int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops) |
1648 | { | 1691 | { |
1649 | struct rio_mport *port; | 1692 | struct rio_mport *port; |
1693 | struct rio_scan_node *scan; | ||
1694 | |||
1695 | pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id); | ||
1696 | |||
1697 | if (mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) | ||
1698 | return -EINVAL; | ||
1650 | 1699 | ||
1651 | mutex_lock(&rio_mport_list_lock); | 1700 | mutex_lock(&rio_mport_list_lock); |
1652 | list_for_each_entry(port, &rio_mports, node) { | 1701 | |
1653 | if (port->id == mport_id || mport_id == RIO_MPORT_ANY) { | 1702 | list_for_each_entry(port, &rio_mports, node) |
1654 | if (port->nscan) | 1703 | if (port->id == mport_id || |
1655 | port->nscan = NULL; | 1704 | (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops)) |
1656 | if (mport_id != RIO_MPORT_ANY) | 1705 | port->nscan = NULL; |
1657 | break; | 1706 | |
1707 | list_for_each_entry(scan, &rio_scans, node) | ||
1708 | if (scan->mport_id == mport_id) { | ||
1709 | list_del(&scan->node); | ||
1710 | kfree(scan); | ||
1658 | } | 1711 | } |
1659 | } | 1712 | |
1660 | mutex_unlock(&rio_mport_list_lock); | 1713 | mutex_unlock(&rio_mport_list_lock); |
1661 | 1714 | ||
1662 | return 0; | 1715 | return 0; |
1663 | } | 1716 | } |
1664 | EXPORT_SYMBOL_GPL(rio_unregister_scan); | 1717 | EXPORT_SYMBOL_GPL(rio_unregister_scan); |
1665 | 1718 | ||
1719 | /** | ||
1720 | * rio_mport_scan - execute enumeration/discovery on the specified mport | ||
1721 | * @mport_id: number (ID) of mport device | ||
1722 | */ | ||
1723 | int rio_mport_scan(int mport_id) | ||
1724 | { | ||
1725 | struct rio_mport *port = NULL; | ||
1726 | int rc; | ||
1727 | |||
1728 | mutex_lock(&rio_mport_list_lock); | ||
1729 | list_for_each_entry(port, &rio_mports, node) { | ||
1730 | if (port->id == mport_id) | ||
1731 | goto found; | ||
1732 | } | ||
1733 | mutex_unlock(&rio_mport_list_lock); | ||
1734 | return -ENODEV; | ||
1735 | found: | ||
1736 | if (!port->nscan) { | ||
1737 | mutex_unlock(&rio_mport_list_lock); | ||
1738 | return -EINVAL; | ||
1739 | } | ||
1740 | |||
1741 | if (!try_module_get(port->nscan->owner)) { | ||
1742 | mutex_unlock(&rio_mport_list_lock); | ||
1743 | return -ENODEV; | ||
1744 | } | ||
1745 | |||
1746 | mutex_unlock(&rio_mport_list_lock); | ||
1747 | |||
1748 | if (port->host_deviceid >= 0) | ||
1749 | rc = port->nscan->enumerate(port, 0); | ||
1750 | else | ||
1751 | rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT); | ||
1752 | |||
1753 | module_put(port->nscan->owner); | ||
1754 | return rc; | ||
1755 | } | ||
1756 | |||
1666 | static void rio_fixup_device(struct rio_dev *dev) | 1757 | static void rio_fixup_device(struct rio_dev *dev) |
1667 | { | 1758 | { |
1668 | } | 1759 | } |
@@ -1691,7 +1782,10 @@ static void disc_work_handler(struct work_struct *_work) | |||
1691 | work = container_of(_work, struct rio_disc_work, work); | 1782 | work = container_of(_work, struct rio_disc_work, work); |
1692 | pr_debug("RIO: discovery work for mport %d %s\n", | 1783 | pr_debug("RIO: discovery work for mport %d %s\n", |
1693 | work->mport->id, work->mport->name); | 1784 | work->mport->id, work->mport->name); |
1694 | work->mport->nscan->discover(work->mport, 0); | 1785 | if (try_module_get(work->mport->nscan->owner)) { |
1786 | work->mport->nscan->discover(work->mport, 0); | ||
1787 | module_put(work->mport->nscan->owner); | ||
1788 | } | ||
1695 | } | 1789 | } |
1696 | 1790 | ||
1697 | int rio_init_mports(void) | 1791 | int rio_init_mports(void) |
@@ -1710,8 +1804,10 @@ int rio_init_mports(void) | |||
1710 | mutex_lock(&rio_mport_list_lock); | 1804 | mutex_lock(&rio_mport_list_lock); |
1711 | list_for_each_entry(port, &rio_mports, node) { | 1805 | list_for_each_entry(port, &rio_mports, node) { |
1712 | if (port->host_deviceid >= 0) { | 1806 | if (port->host_deviceid >= 0) { |
1713 | if (port->nscan) | 1807 | if (port->nscan && try_module_get(port->nscan->owner)) { |
1714 | port->nscan->enumerate(port, 0); | 1808 | port->nscan->enumerate(port, 0); |
1809 | module_put(port->nscan->owner); | ||
1810 | } | ||
1715 | } else | 1811 | } else |
1716 | n++; | 1812 | n++; |
1717 | } | 1813 | } |
@@ -1725,7 +1821,7 @@ int rio_init_mports(void) | |||
1725 | * for each of them. If the code below fails to allocate needed | 1821 | * for each of them. If the code below fails to allocate needed |
1726 | * resources, exit without error to keep results of enumeration | 1822 | * resources, exit without error to keep results of enumeration |
1727 | * process (if any). | 1823 | * process (if any). |
1728 | * TODO: Implement restart of dicovery process for all or | 1824 | * TODO: Implement restart of discovery process for all or |
1729 | * individual discovering mports. | 1825 | * individual discovering mports. |
1730 | */ | 1826 | */ |
1731 | rio_wq = alloc_workqueue("riodisc", 0, 0); | 1827 | rio_wq = alloc_workqueue("riodisc", 0, 0); |
@@ -1751,9 +1847,9 @@ int rio_init_mports(void) | |||
1751 | n++; | 1847 | n++; |
1752 | } | 1848 | } |
1753 | } | 1849 | } |
1754 | mutex_unlock(&rio_mport_list_lock); | ||
1755 | 1850 | ||
1756 | flush_workqueue(rio_wq); | 1851 | flush_workqueue(rio_wq); |
1852 | mutex_unlock(&rio_mport_list_lock); | ||
1757 | pr_debug("RIO: destroy discovery workqueue\n"); | 1853 | pr_debug("RIO: destroy discovery workqueue\n"); |
1758 | destroy_workqueue(rio_wq); | 1854 | destroy_workqueue(rio_wq); |
1759 | kfree(work); | 1855 | kfree(work); |
@@ -1784,6 +1880,8 @@ __setup("riohdid=", rio_hdid_setup); | |||
1784 | 1880 | ||
1785 | int rio_register_mport(struct rio_mport *port) | 1881 | int rio_register_mport(struct rio_mport *port) |
1786 | { | 1882 | { |
1883 | struct rio_scan_node *scan = NULL; | ||
1884 | |||
1787 | if (next_portid >= RIO_MAX_MPORTS) { | 1885 | if (next_portid >= RIO_MAX_MPORTS) { |
1788 | pr_err("RIO: reached specified max number of mports\n"); | 1886 | pr_err("RIO: reached specified max number of mports\n"); |
1789 | return 1; | 1887 | return 1; |
@@ -1792,9 +1890,25 @@ int rio_register_mport(struct rio_mport *port) | |||
1792 | port->id = next_portid++; | 1890 | port->id = next_portid++; |
1793 | port->host_deviceid = rio_get_hdid(port->id); | 1891 | port->host_deviceid = rio_get_hdid(port->id); |
1794 | port->nscan = NULL; | 1892 | port->nscan = NULL; |
1893 | |||
1795 | mutex_lock(&rio_mport_list_lock); | 1894 | mutex_lock(&rio_mport_list_lock); |
1796 | list_add_tail(&port->node, &rio_mports); | 1895 | list_add_tail(&port->node, &rio_mports); |
1896 | |||
1897 | /* | ||
1898 | * Check if there are any registered enumeration/discovery operations | ||
1899 | * that have to be attached to the added mport. | ||
1900 | */ | ||
1901 | list_for_each_entry(scan, &rio_scans, node) { | ||
1902 | if (port->id == scan->mport_id || | ||
1903 | scan->mport_id == RIO_MPORT_ANY) { | ||
1904 | port->nscan = scan->ops; | ||
1905 | if (port->id == scan->mport_id) | ||
1906 | break; | ||
1907 | } | ||
1908 | } | ||
1797 | mutex_unlock(&rio_mport_list_lock); | 1909 | mutex_unlock(&rio_mport_list_lock); |
1910 | |||
1911 | pr_debug("RIO: %s %s id=%d\n", __func__, port->name, port->id); | ||
1798 | return 0; | 1912 | return 0; |
1799 | } | 1913 | } |
1800 | 1914 | ||
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index d59587762c76..085215cd8502 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h | |||
@@ -42,9 +42,10 @@ extern int rio_add_device(struct rio_dev *rdev); | |||
42 | extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid, | 42 | extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid, |
43 | u8 hopcount, u8 port_num); | 43 | u8 hopcount, u8 port_num); |
44 | extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops); | 44 | extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops); |
45 | extern int rio_unregister_scan(int mport_id); | 45 | extern int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops); |
46 | extern void rio_attach_device(struct rio_dev *rdev); | 46 | extern void rio_attach_device(struct rio_dev *rdev); |
47 | extern struct rio_mport *rio_find_mport(int mport_id); | 47 | extern struct rio_mport *rio_find_mport(int mport_id); |
48 | extern int rio_mport_scan(int mport_id); | ||
48 | 49 | ||
49 | /* Structures internal to the RIO core code */ | 50 | /* Structures internal to the RIO core code */ |
50 | extern struct device_attribute rio_dev_attrs[]; | 51 | extern struct device_attribute rio_dev_attrs[]; |