[PATCH 2/3] rapidio: add enumeration/discovery start from user space

From: Alexandre Bounine
Date: Wed Apr 24 2013 - 10:46:19 EST


Add RapidIO enumeration/discovery start from user space.
User space start allows to defer RapidIO fabric scan until the moment when all
participating endpoints are initialized avoiding mandatory synchronized start
of all endpoints (which may be challenging in systems with large number of
RapidIO endpoints).

For compatibility with the existing RapidIO subsystem implementation, automatic
boot time enumeration/discovery start can be configured in by selecting
CONFIG_RAPIDIO_ENUM_AUTO option.

Signed-off-by: Alexandre Bounine <alexandre.bounine@xxxxxxx>
Cc: Matt Porter <mporter@xxxxxxxxxxxxxxxxxxx>
Cc: Li Yang <leoli@xxxxxxxxxxxxx>
Cc: Kumar Gala <galak@xxxxxxxxxxxxxxxxxxx>
Cc: Andre van Herk <andre.van.herk@xxxxxxxxxxx>
Cc: Micha Nelissen <micha.nelissen@xxxxxxxxxxx>
---
drivers/rapidio/Kconfig | 9 ++++++++
drivers/rapidio/rio-driver.c | 1 +
drivers/rapidio/rio-scan.c | 24 +++++++++++++++++++--
drivers/rapidio/rio-sysfs.c | 45 ++++++++++++++++++++++++++++++++++++++++++
drivers/rapidio/rio.c | 26 ++++++++++++++++++++++-
drivers/rapidio/rio.h | 2 +
include/linux/rio.h | 9 ++++++-
7 files changed, 109 insertions(+), 7 deletions(-)

diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
index e392cab..8b7f92d 100644
--- a/drivers/rapidio/Kconfig
+++ b/drivers/rapidio/Kconfig
@@ -66,4 +66,13 @@ config RAPIDIO_ENUM_BASIC

endchoice

+config RAPIDIO_ENUM_AUTO
+ bool "Automatic RapidIO enumeration/discovery start"
+ depends on RAPIDIO && RAPIDIO_ENUM_BASIC = y
+ help
+ Say Y if you want RapidIO subsystem to start fabric enumeration and
+ discovery automatically during kernel initialization time.
+ If you are unsure, say N here. You will be able to start RapidIO
+ fabric enumeration or discovery later by a user request.
+
source "drivers/rapidio/switches/Kconfig"
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index 55850bb..a0c8755 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -207,6 +207,7 @@ struct bus_type rio_bus_type = {
.name = "rapidio",
.match = rio_match_bus,
.dev_attrs = rio_dev_attrs,
+ .bus_attrs = rio_bus_attrs,
.probe = rio_device_probe,
.remove = rio_device_remove,
};
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 33fc332..3e371b1 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -1134,19 +1134,30 @@ static void rio_pw_enable(struct rio_mport *port, int enable)
/**
* rio_enum_mport- Start enumeration through a master port
* @mport: Master port to send transactions
+ * @flags: Enumeration control flags
*
* Starts the enumeration process. If somebody has enumerated our
* master port device, then give up. If not and we have an active
* link, then start recursive peer enumeration. Returns %0 if
* enumeration succeeds or %-EBUSY if enumeration fails.
*/
-int rio_enum_mport(struct rio_mport *mport)
+int rio_enum_mport(struct rio_mport *mport, u32 flags)
{
struct rio_net *net = NULL;
int rc = 0;

printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id,
mport->name);
+
+ /*
+ * To avoid multiple start requests (repeat enumeration is not supported
+ * by this method) check if enumeration/discovery was performed for this
+ * mport: if mport was added into the list of mports for a net exit
+ * with error.
+ */
+ if (mport->nnode.next || mport->nnode.prev)
+ return -EBUSY;
+
/* If somebody else enumerated our master port device, bail. */
if (rio_enum_host(mport) < 0) {
printk(KERN_INFO
@@ -1236,14 +1247,16 @@ static void rio_build_route_tables(struct rio_net *net)
/**
* rio_disc_mport- Start discovery through a master port
* @mport: Master port to send transactions
+ * @flags: discovery control flags
*
* Starts the discovery process. If we have an active link,
- * then wait for the signal that enumeration is complete.
+ * then wait for the signal that enumeration is complete (if wait
+ * is allowed).
* When enumeration completion is signaled, start recursive
* peer discovery. Returns %0 if discovery succeeds or %-EBUSY
* on failure.
*/
-int rio_disc_mport(struct rio_mport *mport)
+int rio_disc_mport(struct rio_mport *mport, u32 flags)
{
struct rio_net *net = NULL;
unsigned long to_end;
@@ -1253,6 +1266,11 @@ int rio_disc_mport(struct rio_mport *mport)

/* If master port has an active link, allocate net and discover peers */
if (rio_mport_is_active(mport)) {
+ if (rio_enum_complete(mport))
+ goto enum_done;
+ else if (flags & RIO_SCAN_ENUM_NO_WAIT)
+ return -EAGAIN;
+
pr_debug("RIO: wait for enumeration to complete...\n");

to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ;
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 4dbe360..66d4acd 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -285,3 +285,48 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
}
}
+
+static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
+ size_t count)
+{
+ long val;
+ struct rio_mport *port = NULL;
+ int rc;
+
+ if (kstrtol(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ if (val == RIO_MPORT_ANY) {
+ rc = rio_init_mports();
+ goto exit;
+ }
+
+ if (val < 0 || val >= RIO_MAX_MPORTS)
+ return -EINVAL;
+
+ port = rio_find_mport((int)val);
+
+ if (!port) {
+ pr_debug("RIO: %s: mport_%d not available\n",
+ __func__, (int)val);
+ return -EINVAL;
+ }
+
+ if (!port->nscan)
+ return -EINVAL;
+
+ if (port->host_deviceid >= 0)
+ rc = port->nscan->enumerate(port, 0);
+ else
+ rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT);
+exit:
+ if (!rc)
+ rc = count;
+
+ return rc;
+}
+
+struct bus_attribute rio_bus_attrs[] = {
+ __ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store),
+ __ATTR_NULL
+};
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index e36628a..3bfbcec 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -1382,6 +1382,26 @@ EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg);
#endif /* CONFIG_RAPIDIO_DMA_ENGINE */

/**
+ * rio_find_mport - find RIO mport by its ID
+ * @mport_id: number (ID) of mport device
+ *
+ * Given a RIO mport number, the desired mport is located
+ * in the global list of mports. If the mport is found, a pointer to its
+ * data structure is returned. If no mport is found, %NULL is returned.
+ */
+struct rio_mport *rio_find_mport(int mport_id)
+{
+ struct rio_mport *port = NULL;
+
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->id == mport_id)
+ return port;
+ }
+
+ return NULL;
+}
+
+/**
* rio_register_scan - enumeration/discovery method registration interface
* @mport_id: mport device ID for which fabric scan routine has to be set
* (RIO_MPORT_ANY = set for all available mports)
@@ -1470,7 +1490,7 @@ static void disc_work_handler(struct work_struct *_work)
work = container_of(_work, struct rio_disc_work, work);
pr_debug("RIO: discovery work for mport %d %s\n",
work->mport->id, work->mport->name);
- work->mport->nscan->discover(work->mport);
+ work->mport->nscan->discover(work->mport, 0);
}

int rio_init_mports(void)
@@ -1489,7 +1509,7 @@ int rio_init_mports(void)
list_for_each_entry(port, &rio_mports, node) {
if (port->host_deviceid >= 0) {
if (port->nscan)
- port->nscan->enumerate(port);
+ port->nscan->enumerate(port, 0);
} else
n++;
}
@@ -1539,7 +1559,9 @@ no_disc:
return 0;
}

+#ifdef CONFIG_RAPIDIO_ENUM_AUTO
device_initcall_sync(rio_init_mports);
+#endif

static int hdids[RIO_MAX_MPORTS + 1];

diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index d44e7e6..bdd339e 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -45,9 +45,11 @@ extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid,
extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops);
extern int rio_unregister_scan(int mport_id);
extern void rio_attach_device(struct rio_dev *rdev);
+extern struct rio_mport *rio_find_mport(int mport_id);

/* Structures internal to the RIO core code */
extern struct device_attribute rio_dev_attrs[];
+extern struct bus_attribute rio_bus_attrs[];
extern spinlock_t rio_global_list_lock;

extern struct rio_switch_ops __start_rio_switch_ops[];
diff --git a/include/linux/rio.h b/include/linux/rio.h
index 30a48a8..a29a35b 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -266,6 +266,11 @@ struct rio_mport {
struct rio_scan *nscan;
};

+/*
+ * Enumeration/discovery control flags
+ */
+#define RIO_SCAN_ENUM_NO_WAIT 0x00000001 /* Do not wait for enum completed */
+
struct rio_id_table {
u16 start; /* logical minimal id */
u32 max; /* max number of IDs in table */
@@ -468,8 +473,8 @@ static inline struct rio_mport *dma_to_mport(struct dma_device *ddev)
* @discover: Callback to perform RapidIO fabric discovery.
*/
struct rio_scan {
- int (*enumerate)(struct rio_mport *mport);
- int (*discover)(struct rio_mport *mport);
+ int (*enumerate)(struct rio_mport *mport, u32 flags);
+ int (*discover)(struct rio_mport *mport, u32 flags);
};

/* Architecture and hardware-specific functions */
--
1.7.8.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/