[PATCH] rapidio: fix multi-switch enumeration
This patch contains two fixes for RapisIO enumeration logic: 1. Fix enumeration in configurations with multiple switches. The patch adds: a. Enumeration of an empty switch. Empty switch is a switch that does not have any endpoint devices attached to it (except host device or previous switch in a chain). New code assigns a phony destination ID associated with the switch and sets up corresponding routes. b. Adds a second pass to the enumeration to setup routes to devices discovered after switch was scanned. 2. Fix enumeration failure when riohdid parameter has non-zero value. Current version fails to setup response path to the host when it has destination ID other that 0. Signed-off-by: Alexandre Bounine <alexandreb@tundra.com> Acked-by: Matt Porter <mporter@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
d5698c28b6
commit
c70555b051
|
@ -326,14 +326,17 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
|
|||
rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR,
|
||||
&rdev->dst_ops);
|
||||
|
||||
if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)
|
||||
&& do_enum) {
|
||||
rio_set_device_id(port, destid, hopcount, next_destid);
|
||||
rdev->destid = next_destid++;
|
||||
if (next_destid == port->host_deviceid)
|
||||
next_destid++;
|
||||
if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) {
|
||||
if (do_enum) {
|
||||
rio_set_device_id(port, destid, hopcount, next_destid);
|
||||
rdev->destid = next_destid++;
|
||||
if (next_destid == port->host_deviceid)
|
||||
next_destid++;
|
||||
} else
|
||||
rdev->destid = rio_get_device_id(port, destid, hopcount);
|
||||
} else
|
||||
rdev->destid = rio_get_device_id(port, destid, hopcount);
|
||||
/* Switch device has an associated destID */
|
||||
rdev->destid = RIO_INVALID_DESTID;
|
||||
|
||||
/* If a PE has both switch and other functions, show it as a switch */
|
||||
if (rio_is_switch(rdev)) {
|
||||
|
@ -347,7 +350,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
|
|||
}
|
||||
rswitch->switchid = next_switchid;
|
||||
rswitch->hopcount = hopcount;
|
||||
rswitch->destid = 0xffff;
|
||||
rswitch->destid = destid;
|
||||
/* Initialize switch route table */
|
||||
for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++)
|
||||
rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
|
||||
|
@ -422,7 +425,7 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
|
|||
/**
|
||||
* rio_route_add_entry- Add a route entry to a switch routing table
|
||||
* @mport: Master port to send transaction
|
||||
* @rdev: Switch device
|
||||
* @rswitch: Switch device
|
||||
* @table: Routing table ID
|
||||
* @route_destid: Destination ID to be routed
|
||||
* @route_port: Port number to be routed
|
||||
|
@ -434,18 +437,18 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
|
|||
* %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
|
||||
* on failure.
|
||||
*/
|
||||
static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev,
|
||||
static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
|
||||
u16 table, u16 route_destid, u8 route_port)
|
||||
{
|
||||
return rdev->rswitch->add_entry(mport, rdev->rswitch->destid,
|
||||
rdev->rswitch->hopcount, table,
|
||||
return rswitch->add_entry(mport, rswitch->destid,
|
||||
rswitch->hopcount, table,
|
||||
route_destid, route_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* rio_route_get_entry- Read a route entry in a switch routing table
|
||||
* @mport: Master port to send transaction
|
||||
* @rdev: Switch device
|
||||
* @rswitch: Switch device
|
||||
* @table: Routing table ID
|
||||
* @route_destid: Destination ID to be routed
|
||||
* @route_port: Pointer to read port number into
|
||||
|
@ -458,11 +461,11 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev,
|
|||
* on failure.
|
||||
*/
|
||||
static int
|
||||
rio_route_get_entry(struct rio_mport *mport, struct rio_dev *rdev, u16 table,
|
||||
rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table,
|
||||
u16 route_destid, u8 * route_port)
|
||||
{
|
||||
return rdev->rswitch->get_entry(mport, rdev->rswitch->destid,
|
||||
rdev->rswitch->hopcount, table,
|
||||
return rswitch->get_entry(mport, rswitch->destid,
|
||||
rswitch->hopcount, table,
|
||||
route_destid, route_port);
|
||||
}
|
||||
|
||||
|
@ -552,6 +555,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
|
|||
int port_num;
|
||||
int num_ports;
|
||||
int cur_destid;
|
||||
int sw_destid;
|
||||
int sw_inport;
|
||||
struct rio_dev *rdev;
|
||||
u16 destid;
|
||||
int tmp;
|
||||
|
@ -594,15 +599,17 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
|
|||
|
||||
if (rio_is_switch(rdev)) {
|
||||
next_switchid++;
|
||||
sw_inport = rio_get_swpinfo_inport(port, RIO_ANY_DESTID, hopcount);
|
||||
rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
|
||||
port->host_deviceid, sw_inport);
|
||||
rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
|
||||
|
||||
for (destid = 0; destid < next_destid; destid++) {
|
||||
rio_route_add_entry(port, rdev, RIO_GLOBAL_TABLE,
|
||||
destid, rio_get_swpinfo_inport(port,
|
||||
RIO_ANY_DESTID,
|
||||
hopcount));
|
||||
rdev->rswitch->route_table[destid] =
|
||||
rio_get_swpinfo_inport(port, RIO_ANY_DESTID,
|
||||
hopcount);
|
||||
if (destid == port->host_deviceid)
|
||||
continue;
|
||||
rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
|
||||
destid, sw_inport);
|
||||
rdev->rswitch->route_table[destid] = sw_inport;
|
||||
}
|
||||
|
||||
num_ports =
|
||||
|
@ -610,9 +617,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
|
|||
pr_debug(
|
||||
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
|
||||
rio_name(rdev), rdev->vid, rdev->did, num_ports);
|
||||
sw_destid = next_destid;
|
||||
for (port_num = 0; port_num < num_ports; port_num++) {
|
||||
if (rio_get_swpinfo_inport
|
||||
(port, RIO_ANY_DESTID, hopcount) == port_num)
|
||||
if (sw_inport == port_num)
|
||||
continue;
|
||||
|
||||
cur_destid = next_destid;
|
||||
|
@ -622,7 +629,7 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
|
|||
pr_debug(
|
||||
"RIO: scanning device on port %d\n",
|
||||
port_num);
|
||||
rio_route_add_entry(port, rdev,
|
||||
rio_route_add_entry(port, rdev->rswitch,
|
||||
RIO_GLOBAL_TABLE,
|
||||
RIO_ANY_DESTID, port_num);
|
||||
|
||||
|
@ -633,7 +640,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
|
|||
if (next_destid > cur_destid) {
|
||||
for (destid = cur_destid;
|
||||
destid < next_destid; destid++) {
|
||||
rio_route_add_entry(port, rdev,
|
||||
if (destid == port->host_deviceid)
|
||||
continue;
|
||||
rio_route_add_entry(port, rdev->rswitch,
|
||||
RIO_GLOBAL_TABLE,
|
||||
destid,
|
||||
port_num);
|
||||
|
@ -641,10 +650,18 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
|
|||
route_table[destid] =
|
||||
port_num;
|
||||
}
|
||||
rdev->rswitch->destid = cur_destid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for empty switch */
|
||||
if (next_destid == sw_destid) {
|
||||
next_destid++;
|
||||
if (next_destid == port->host_deviceid)
|
||||
next_destid++;
|
||||
}
|
||||
|
||||
rdev->rswitch->destid = sw_destid;
|
||||
} else
|
||||
pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",
|
||||
rio_name(rdev), rdev->vid, rdev->did);
|
||||
|
@ -721,7 +738,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
|
|||
port_num);
|
||||
for (ndestid = 0; ndestid < RIO_ANY_DESTID;
|
||||
ndestid++) {
|
||||
rio_route_get_entry(port, rdev,
|
||||
rio_route_get_entry(port, rdev->rswitch,
|
||||
RIO_GLOBAL_TABLE,
|
||||
ndestid,
|
||||
&route_port);
|
||||
|
@ -797,6 +814,44 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
|
|||
return net;
|
||||
}
|
||||
|
||||
/**
|
||||
* rio_update_route_tables- Updates route tables in switches
|
||||
* @port: Master port associated with the RIO network
|
||||
*
|
||||
* For each enumerated device, ensure that each switch in a system
|
||||
* has correct routing entries. Add routes for devices that where
|
||||
* unknown dirung the first enumeration pass through the switch.
|
||||
*/
|
||||
static void rio_update_route_tables(struct rio_mport *port)
|
||||
{
|
||||
struct rio_dev *rdev;
|
||||
struct rio_switch *rswitch;
|
||||
u8 sport;
|
||||
u16 destid;
|
||||
|
||||
list_for_each_entry(rdev, &rio_devices, global_list) {
|
||||
|
||||
destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid;
|
||||
|
||||
list_for_each_entry(rswitch, &rio_switches, node) {
|
||||
|
||||
if (rio_is_switch(rdev) && (rdev->rswitch == rswitch))
|
||||
continue;
|
||||
|
||||
if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {
|
||||
|
||||
sport = rio_get_swpinfo_inport(port,
|
||||
rswitch->destid, rswitch->hopcount);
|
||||
|
||||
if (rswitch->add_entry) {
|
||||
rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport);
|
||||
rswitch->route_table[destid] = sport;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rio_enum_mport- Start enumeration through a master port
|
||||
* @mport: Master port to send transactions
|
||||
|
@ -838,6 +893,7 @@ int rio_enum_mport(struct rio_mport *mport)
|
|||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
rio_update_route_tables(mport);
|
||||
rio_clear_locks(mport);
|
||||
} else {
|
||||
printk(KERN_INFO "RIO: master port %d link inactive\n",
|
||||
|
@ -865,8 +921,8 @@ static void rio_build_route_tables(void)
|
|||
if (rio_is_switch(rdev))
|
||||
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) {
|
||||
if (rio_route_get_entry
|
||||
(rdev->net->hport, rdev, RIO_GLOBAL_TABLE, i,
|
||||
&sport) < 0)
|
||||
(rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,
|
||||
i, &sport) < 0)
|
||||
continue;
|
||||
rdev->rswitch->route_table[i] = sport;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#define RIO_ANY_DESTID 0xff
|
||||
#define RIO_NO_HOPCOUNT -1
|
||||
#define RIO_INVALID_DESTID 0xffff
|
||||
|
||||
#define RIO_MAX_MPORT_RESOURCES 16
|
||||
#define RIO_MAX_DEV_RESOURCES 16
|
||||
|
|
Loading…
Reference in New Issue