Commit bc8fcfea authored by Alexandre Bounine's avatar Alexandre Bounine Committed by Linus Torvalds

rapidio: add enumeration/discovery start from user space

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).
Signed-off-by: default avatarAlexandre 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>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a11650e1
...@@ -207,6 +207,7 @@ struct bus_type rio_bus_type = { ...@@ -207,6 +207,7 @@ struct bus_type rio_bus_type = {
.name = "rapidio", .name = "rapidio",
.match = rio_match_bus, .match = rio_match_bus,
.dev_attrs = rio_dev_attrs, .dev_attrs = rio_dev_attrs,
.bus_attrs = rio_bus_attrs,
.probe = rio_device_probe, .probe = rio_device_probe,
.remove = rio_device_remove, .remove = rio_device_remove,
}; };
......
...@@ -1134,19 +1134,30 @@ static void rio_pw_enable(struct rio_mport *port, int enable) ...@@ -1134,19 +1134,30 @@ static void rio_pw_enable(struct rio_mport *port, int enable)
/** /**
* rio_enum_mport- Start enumeration through a master port * rio_enum_mport- Start enumeration through a master port
* @mport: Master port to send transactions * @mport: Master port to send transactions
* @flags: Enumeration control flags
* *
* Starts the enumeration process. If somebody has enumerated our * Starts the enumeration process. If somebody has enumerated our
* master port device, then give up. If not and we have an active * master port device, then give up. If not and we have an active
* link, then start recursive peer enumeration. Returns %0 if * link, then start recursive peer enumeration. Returns %0 if
* enumeration succeeds or %-EBUSY if enumeration fails. * 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; struct rio_net *net = NULL;
int rc = 0; int rc = 0;
printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id, printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id,
mport->name); 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 somebody else enumerated our master port device, bail. */
if (rio_enum_host(mport) < 0) { if (rio_enum_host(mport) < 0) {
printk(KERN_INFO printk(KERN_INFO
...@@ -1236,14 +1247,16 @@ static void rio_build_route_tables(struct rio_net *net) ...@@ -1236,14 +1247,16 @@ static void rio_build_route_tables(struct rio_net *net)
/** /**
* rio_disc_mport- Start discovery through a master port * rio_disc_mport- Start discovery through a master port
* @mport: Master port to send transactions * @mport: Master port to send transactions
* @flags: discovery control flags
* *
* Starts the discovery process. If we have an active link, * 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 * When enumeration completion is signaled, start recursive
* peer discovery. Returns %0 if discovery succeeds or %-EBUSY * peer discovery. Returns %0 if discovery succeeds or %-EBUSY
* on failure. * 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; struct rio_net *net = NULL;
unsigned long to_end; unsigned long to_end;
...@@ -1253,6 +1266,11 @@ int rio_disc_mport(struct rio_mport *mport) ...@@ -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 master port has an active link, allocate net and discover peers */
if (rio_mport_is_active(mport)) { 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"); pr_debug("RIO: wait for enumeration to complete...\n");
to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ;
......
...@@ -285,3 +285,48 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev) ...@@ -285,3 +285,48 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE); 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
};
...@@ -1382,6 +1382,30 @@ EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg); ...@@ -1382,6 +1382,30 @@ EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg);
#endif /* CONFIG_RAPIDIO_DMA_ENGINE */ #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;
mutex_lock(&rio_mport_list_lock);
list_for_each_entry(port, &rio_mports, node) {
if (port->id == mport_id)
goto found;
}
port = NULL;
found:
mutex_unlock(&rio_mport_list_lock);
return port;
}
/** /**
* rio_register_scan - enumeration/discovery method registration interface * rio_register_scan - enumeration/discovery method registration interface
* @mport_id: mport device ID for which fabric scan routine has to be set * @mport_id: mport device ID for which fabric scan routine has to be set
...@@ -1475,7 +1499,7 @@ static void disc_work_handler(struct work_struct *_work) ...@@ -1475,7 +1499,7 @@ static void disc_work_handler(struct work_struct *_work)
work = container_of(_work, struct rio_disc_work, work); work = container_of(_work, struct rio_disc_work, work);
pr_debug("RIO: discovery work for mport %d %s\n", pr_debug("RIO: discovery work for mport %d %s\n",
work->mport->id, work->mport->name); work->mport->id, work->mport->name);
work->mport->nscan->discover(work->mport); work->mport->nscan->discover(work->mport, 0);
} }
int rio_init_mports(void) int rio_init_mports(void)
...@@ -1495,7 +1519,7 @@ int rio_init_mports(void) ...@@ -1495,7 +1519,7 @@ int rio_init_mports(void)
list_for_each_entry(port, &rio_mports, node) { list_for_each_entry(port, &rio_mports, node) {
if (port->host_deviceid >= 0) { if (port->host_deviceid >= 0) {
if (port->nscan) if (port->nscan)
port->nscan->enumerate(port); port->nscan->enumerate(port, 0);
} else } else
n++; n++;
} }
......
...@@ -45,9 +45,11 @@ extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid, ...@@ -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_register_scan(int mport_id, struct rio_scan *scan_ops);
extern int rio_unregister_scan(int mport_id); extern int rio_unregister_scan(int mport_id);
extern void rio_attach_device(struct rio_dev *rdev); 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 */ /* Structures internal to the RIO core code */
extern struct device_attribute rio_dev_attrs[]; extern struct device_attribute rio_dev_attrs[];
extern struct bus_attribute rio_bus_attrs[];
extern struct rio_switch_ops __start_rio_switch_ops[]; extern struct rio_switch_ops __start_rio_switch_ops[];
extern struct rio_switch_ops __end_rio_switch_ops[]; extern struct rio_switch_ops __end_rio_switch_ops[];
......
...@@ -265,6 +265,11 @@ struct rio_mport { ...@@ -265,6 +265,11 @@ struct rio_mport {
struct rio_scan *nscan; 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 { struct rio_id_table {
u16 start; /* logical minimal id */ u16 start; /* logical minimal id */
u32 max; /* max number of IDs in table */ u32 max; /* max number of IDs in table */
...@@ -467,8 +472,8 @@ static inline struct rio_mport *dma_to_mport(struct dma_device *ddev) ...@@ -467,8 +472,8 @@ static inline struct rio_mport *dma_to_mport(struct dma_device *ddev)
* @discover: Callback to perform RapidIO fabric discovery. * @discover: Callback to perform RapidIO fabric discovery.
*/ */
struct rio_scan { struct rio_scan {
int (*enumerate)(struct rio_mport *mport); int (*enumerate)(struct rio_mport *mport, u32 flags);
int (*discover)(struct rio_mport *mport); int (*discover)(struct rio_mport *mport, u32 flags);
}; };
/* Architecture and hardware-specific functions */ /* Architecture and hardware-specific functions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment