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: Alexandre Bounine <alexandre.bounine@idt.com> Tested-by: Thomas 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
07590ff039
commit
818a04a0bb
@ -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)
|
|||||||
* @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)
|
|||||||
* %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
|
|||||||
* @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
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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
|
||||||
|
Loading…
Reference in New Issue
Block a user