Commit 818a04a0 authored by Alexandre Bounine's avatar Alexandre Bounine Committed by Linus Torvalds

rapidio: add switch locking during discovery

Add switch access locking during RapidIO discovery.  Access lock is
required when reading switch routing table contents due to indexed
mechanism of RT addressing.
Signed-off-by: default avatarAlexandre Bounine <alexandre.bounine@idt.com>
Tested-by: default avatarThomas Moll <thomas.moll@sysgo.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Li Yang <leoli@freescale.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 07590ff0
...@@ -456,6 +456,80 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) ...@@ -456,6 +456,80 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
return (result & PORT_N_ERR_STS_PORT_OK); return (result & PORT_N_ERR_STS_PORT_OK);
} }
/**
* rio_lock_device - Acquires host device lock for specified device
* @port: Master port to send transaction
* @destid: Destination ID for device/switch
* @hopcount: Hopcount to reach switch
* @wait_ms: Max wait time in msec (0 = no timeout)
*
* Attepts to acquire host device lock for specified device
* Returns 0 if device lock acquired or EINVAL if timeout expires.
*/
static int
rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms)
{
u32 result;
int tcnt = 0;
/* Attempt to acquire device lock */
rio_mport_write_config_32(port, destid, hopcount,
RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
rio_mport_read_config_32(port, destid, hopcount,
RIO_HOST_DID_LOCK_CSR, &result);
while (result != port->host_deviceid) {
if (wait_ms != 0 && tcnt == wait_ms) {
pr_debug("RIO: timeout when locking device %x:%x\n",
destid, hopcount);
return -EINVAL;
}
/* Delay a bit */
mdelay(1);
tcnt++;
/* Try to acquire device lock again */
rio_mport_write_config_32(port, destid,
hopcount,
RIO_HOST_DID_LOCK_CSR,
port->host_deviceid);
rio_mport_read_config_32(port, destid,
hopcount,
RIO_HOST_DID_LOCK_CSR, &result);
}
return 0;
}
/**
* rio_unlock_device - Releases host device lock for specified device
* @port: Master port to send transaction
* @destid: Destination ID for device/switch
* @hopcount: Hopcount to reach switch
*
* Returns 0 if device lock released or EINVAL if fails.
*/
static int
rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
{
u32 result;
/* Release device lock */
rio_mport_write_config_32(port, destid,
hopcount,
RIO_HOST_DID_LOCK_CSR,
port->host_deviceid);
rio_mport_read_config_32(port, destid, hopcount,
RIO_HOST_DID_LOCK_CSR, &result);
if ((result & 0xffff) != 0xffff) {
pr_debug("RIO: badness when releasing device lock %x:%x\n",
destid, hopcount);
return -EINVAL;
}
return 0;
}
/** /**
* rio_route_add_entry- Add a route entry to a switch routing table * rio_route_add_entry- Add a route entry to a switch routing table
* @mport: Master port to send transaction * @mport: Master port to send transaction
...@@ -463,6 +537,7 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) ...@@ -463,6 +537,7 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
* @table: Routing table ID * @table: Routing table ID
* @route_destid: Destination ID to be routed * @route_destid: Destination ID to be routed
* @route_port: Port number to be routed * @route_port: Port number to be routed
* @lock: lock switch device flag
* *
* Calls the switch specific add_entry() method to add a route entry * Calls the switch specific add_entry() method to add a route entry
* on a switch. The route table can be specified using the @table * on a switch. The route table can be specified using the @table
...@@ -471,12 +546,26 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) ...@@ -471,12 +546,26 @@ 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 * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
* on failure. * on failure.
*/ */
static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, static int
u16 table, u16 route_destid, u8 route_port) rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
u16 table, u16 route_destid, u8 route_port, int lock)
{ {
return rswitch->add_entry(mport, rswitch->destid, int rc;
if (lock) {
rc = rio_lock_device(mport, rswitch->destid,
rswitch->hopcount, 1000);
if (rc)
return rc;
}
rc = rswitch->add_entry(mport, rswitch->destid,
rswitch->hopcount, table, rswitch->hopcount, table,
route_destid, route_port); route_destid, route_port);
if (lock)
rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
return rc;
} }
/** /**
...@@ -486,6 +575,7 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit ...@@ -486,6 +575,7 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit
* @table: Routing table ID * @table: Routing table ID
* @route_destid: Destination ID to be routed * @route_destid: Destination ID to be routed
* @route_port: Pointer to read port number into * @route_port: Pointer to read port number into
* @lock: lock switch device flag
* *
* Calls the switch specific get_entry() method to read a route entry * Calls the switch specific get_entry() method to read a route entry
* in a switch. The route table can be specified using the @table * in a switch. The route table can be specified using the @table
...@@ -496,11 +586,24 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit ...@@ -496,11 +586,24 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit
*/ */
static int static int
rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table,
u16 route_destid, u8 * route_port) u16 route_destid, u8 *route_port, int lock)
{ {
return rswitch->get_entry(mport, rswitch->destid, int rc;
if (lock) {
rc = rio_lock_device(mport, rswitch->destid,
rswitch->hopcount, 1000);
if (rc)
return rc;
}
rc = rswitch->get_entry(mport, rswitch->destid,
rswitch->hopcount, table, rswitch->hopcount, table,
route_destid, route_port); route_destid, route_port);
if (lock)
rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
return rc;
} }
/** /**
...@@ -640,14 +743,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, ...@@ -640,14 +743,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
sw_inport = rio_get_swpinfo_inport(port, sw_inport = rio_get_swpinfo_inport(port,
RIO_ANY_DESTID(port->sys_size), hopcount); RIO_ANY_DESTID(port->sys_size), hopcount);
rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
port->host_deviceid, sw_inport); port->host_deviceid, sw_inport, 0);
rdev->rswitch->route_table[port->host_deviceid] = sw_inport; rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
for (destid = 0; destid < next_destid; destid++) { for (destid = 0; destid < next_destid; destid++) {
if (destid == port->host_deviceid) if (destid == port->host_deviceid)
continue; continue;
rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
destid, sw_inport); destid, sw_inport, 0);
rdev->rswitch->route_table[destid] = sw_inport; rdev->rswitch->route_table[destid] = sw_inport;
} }
...@@ -673,7 +776,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, ...@@ -673,7 +776,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
rio_route_add_entry(port, rdev->rswitch, rio_route_add_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE, RIO_GLOBAL_TABLE,
RIO_ANY_DESTID(port->sys_size), RIO_ANY_DESTID(port->sys_size),
port_num); port_num, 0);
if (rio_enum_peer(net, port, hopcount + 1) < 0) if (rio_enum_peer(net, port, hopcount + 1) < 0)
return -1; return -1;
...@@ -687,7 +790,8 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, ...@@ -687,7 +790,8 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
rio_route_add_entry(port, rdev->rswitch, rio_route_add_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE, RIO_GLOBAL_TABLE,
destid, destid,
port_num); port_num,
0);
rdev->rswitch-> rdev->rswitch->
route_table[destid] = route_table[destid] =
port_num; port_num;
...@@ -778,17 +882,21 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, ...@@ -778,17 +882,21 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
pr_debug( pr_debug(
"RIO: scanning device on port %d\n", "RIO: scanning device on port %d\n",
port_num); port_num);
rio_lock_device(port, destid, hopcount, 1000);
for (ndestid = 0; for (ndestid = 0;
ndestid < RIO_ANY_DESTID(port->sys_size); ndestid < RIO_ANY_DESTID(port->sys_size);
ndestid++) { ndestid++) {
rio_route_get_entry(port, rdev->rswitch, rio_route_get_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE, RIO_GLOBAL_TABLE,
ndestid, ndestid,
&route_port); &route_port, 0);
if (route_port == port_num) if (route_port == port_num)
break; break;
} }
rio_unlock_device(port, destid, hopcount);
if (rio_disc_peer if (rio_disc_peer
(net, port, ndestid, hopcount + 1) < 0) (net, port, ndestid, hopcount + 1) < 0)
return -1; return -1;
...@@ -889,7 +997,9 @@ static void rio_update_route_tables(struct rio_mport *port) ...@@ -889,7 +997,9 @@ static void rio_update_route_tables(struct rio_mport *port)
rswitch->destid, rswitch->hopcount); rswitch->destid, rswitch->hopcount);
if (rswitch->add_entry) { if (rswitch->add_entry) {
rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport); rio_route_add_entry(port, rswitch,
RIO_GLOBAL_TABLE, destid,
sport, 0);
rswitch->route_table[destid] = sport; rswitch->route_table[destid] = sport;
} }
} }
...@@ -963,15 +1073,22 @@ static void rio_build_route_tables(void) ...@@ -963,15 +1073,22 @@ static void rio_build_route_tables(void)
u8 sport; u8 sport;
list_for_each_entry(rdev, &rio_devices, global_list) list_for_each_entry(rdev, &rio_devices, global_list)
if (rio_is_switch(rdev)) if (rio_is_switch(rdev)) {
for (i = 0; rio_lock_device(rdev->net->hport, rdev->rswitch->destid,
i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); rdev->rswitch->hopcount, 1000);
i++) { for (i = 0;
if (rio_route_get_entry i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
(rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE, i++) {
i, &sport) < 0) if (rio_route_get_entry
continue; (rdev->net->hport, rdev->rswitch,
rdev->rswitch->route_table[i] = sport; RIO_GLOBAL_TABLE, i, &sport, 0) < 0)
continue;
rdev->rswitch->route_table[i] = sport;
}
rio_unlock_device(rdev->net->hport,
rdev->rswitch->destid,
rdev->rswitch->hopcount);
} }
} }
...@@ -1030,6 +1147,13 @@ int __devinit rio_disc_mport(struct rio_mport *mport) ...@@ -1030,6 +1147,13 @@ int __devinit rio_disc_mport(struct rio_mport *mport)
del_timer_sync(&rio_enum_timer); del_timer_sync(&rio_enum_timer);
pr_debug("done\n"); pr_debug("done\n");
/* Read DestID assigned by enumerator */
rio_local_read_config_32(mport, RIO_DID_CSR,
&mport->host_deviceid);
mport->host_deviceid = RIO_GET_DID(mport->sys_size,
mport->host_deviceid);
if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
0) < 0) { 0) < 0) {
printk(KERN_INFO printk(KERN_INFO
......
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