2010-08-13 15:20:34

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 0/9] RapidIO: Set of patches to add Gen2 switches

This set of RapidIO patches adds support for new IDT Gen2 sRIO switch
devices - CPS-1848 and CPS-1616.
Adding these sRIO switches required to implement standard error recovery
mechanism defined by the RapidIO specification.


2010-08-13 15:20:36

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 4/9] RapidIO: Add relation links between RIO device structures

Create back and forward links between RIO devices. These links are intended for
use by error management and hot-plug extensions.

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
drivers/rapidio/rio-scan.c | 55 +++++++++++++++++--------------------------
include/linux/rio.h | 6 ++++
2 files changed, 28 insertions(+), 33 deletions(-)

diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index efe3519..5dc33d1 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -442,7 +442,10 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
if (rio_is_switch(rdev)) {
rio_mport_read_config_32(port, destid, hopcount,
RIO_SWP_INFO_CAR, &swpinfo);
- rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL);
+ rswitch = kzalloc(sizeof(*rswitch) +
+ RIO_GET_TOTAL_PORTS(swpinfo) *
+ sizeof(rswitch->nextdev[0]),
+ GFP_KERNEL);
if (!rswitch)
goto cleanup;
rswitch->switchid = next_switchid;
@@ -450,6 +453,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rswitch->destid = destid;
rswitch->port_ok = 0;
rswitch->inport = (u8)(swpinfo & RIO_SWP_INFO_PORT_NUM_MASK);
+ rswitch->nports = (u8)RIO_GET_TOTAL_PORTS(swpinfo);
rswitch->route_table = kzalloc(sizeof(u8)*
RIO_MAX_ROUTE_ENTRIES(port->sys_size),
GFP_KERNEL);
@@ -721,25 +725,6 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)
}

/**
- * rio_get_swpinfo_tports- Gets total number of ports on the switch
- * @mport: Master port to send transaction
- * @destid: Destination ID associated with the switch
- * @hopcount: Number of hops to the device
- *
- * Returns total numbers of ports implemented by the switch device.
- */
-static u8 rio_get_swpinfo_tports(struct rio_mport *mport, u16 destid,
- u8 hopcount)
-{
- u32 result;
-
- rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR,
- &result);
-
- return RIO_GET_TOTAL_PORTS(result);
-}
-
-/**
* rio_net_add_mport- Add a master port to a RIO network
* @net: RIO network
* @port: Master port to add
@@ -759,15 +744,16 @@ static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port)
* @net: RIO network being enumerated
* @port: Master port to send transactions
* @hopcount: Number of hops into the network
+ * @prev: Previous RIO device connected to the enumerated one
+ * @prev_port: Port on previous RIO device
*
* Recursively enumerates a RIO network. Transactions are sent via the
* master port passed in @port.
*/
static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
- u8 hopcount)
+ u8 hopcount, struct rio_dev *prev, int prev_port)
{
int port_num;
- int num_ports;
int cur_destid;
int sw_destid;
int sw_inport;
@@ -812,6 +798,9 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
if (rdev) {
/* Add device to the global and bus/net specific list. */
list_add_tail(&rdev->net_list, &net->devices);
+ rdev->prev = prev;
+ if (prev && rio_is_switch(prev))
+ prev->rswitch->nextdev[prev_port] = rdev;
} else
return -1;

@@ -830,14 +819,13 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
rdev->rswitch->route_table[destid] = sw_inport;
}

- num_ports =
- rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size),
- hopcount);
pr_debug(
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
- rio_name(rdev), rdev->vid, rdev->did, num_ports);
+ rio_name(rdev), rdev->vid, rdev->did,
+ rdev->rswitch->nports);
sw_destid = next_destid;
- for (port_num = 0; port_num < num_ports; port_num++) {
+ for (port_num = 0;
+ port_num < rdev->rswitch->nports; port_num++) {
/*Enable Input Output Port (transmitter reviever)*/
rio_enable_rx_tx_port(port, 0,
RIO_ANY_DESTID(port->sys_size),
@@ -862,7 +850,8 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
RIO_ANY_DESTID(port->sys_size),
port_num, 0);

- if (rio_enum_peer(net, port, hopcount + 1) < 0)
+ if (rio_enum_peer(net, port, hopcount + 1,
+ rdev, port_num) < 0)
return -1;

/* Update routing tables */
@@ -949,7 +938,6 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
u8 hopcount)
{
u8 port_num, route_port;
- int num_ports;
struct rio_dev *rdev;
u16 ndestid;

@@ -966,11 +954,12 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
/* Associated destid is how we accessed this switch */
rdev->rswitch->destid = destid;

- num_ports = rio_get_swpinfo_tports(port, destid, hopcount);
pr_debug(
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
- rio_name(rdev), rdev->vid, rdev->did, num_ports);
- for (port_num = 0; port_num < num_ports; port_num++) {
+ rio_name(rdev), rdev->vid, rdev->did,
+ rdev->rswitch->nports);
+ for (port_num = 0;
+ port_num < rdev->rswitch->nports; port_num++) {
if (rdev->rswitch->inport == port_num)
continue;

@@ -1163,7 +1152,7 @@ int __devinit rio_enum_mport(struct rio_mport *mport)
/* Enable Input Output Port (transmitter reviever) */
rio_enable_rx_tx_port(mport, 1, 0, 0, 0);

- if (rio_enum_peer(net, mport, 0) < 0) {
+ if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) {
/* A higher priority host won enumeration, bail. */
printk(KERN_INFO
"RIO: master port %d device has lost enumeration to a remote host\n",
diff --git a/include/linux/rio.h b/include/linux/rio.h
index 718075a..754895c 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -98,6 +98,7 @@ union rio_pw_msg;
* @riores: RIO resources this device owns
* @pwcback: port-write callback function for this device
* @destid: Network destination ID
+ * @prev: Previous RIO device connected to the current one
*/
struct rio_dev {
struct list_head global_list; /* node in list of all RIO devices */
@@ -123,6 +124,7 @@ struct rio_dev {
struct resource riores[RIO_MAX_DEV_RESOURCES];
int (*pwcback) (struct rio_dev *rdev, union rio_pw_msg *msg, int step);
u16 destid;
+ struct rio_dev *prev;
};

#define rio_dev_g(n) list_entry(n, struct rio_dev, global_list)
@@ -221,6 +223,7 @@ struct rio_net {
* @hopcount: Hopcount to this switch
* @destid: Associated destid in the path
* @inport: Switch ingress port number
+ * @nports: Total number of ports in the switch
* @route_table: Copy of switch routing table
* @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0
* @add_entry: Callback for switch-specific route add function
@@ -230,6 +233,7 @@ struct rio_net {
* @get_domain: Callback for switch-specific domain get function
* @em_init: Callback for switch-specific error management initialization function
* @em_handle: Callback for switch-specific error management handler function
+ * @nextdev: Array of per-port pointers to the next attached device
*/
struct rio_switch {
struct list_head node;
@@ -237,6 +241,7 @@ struct rio_switch {
u16 hopcount;
u16 destid;
u8 inport;
+ u8 nports;
u8 *route_table;
u32 port_ok;
int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
@@ -251,6 +256,7 @@ struct rio_switch {
u8 *sw_domain);
int (*em_init) (struct rio_dev *dev);
int (*em_handle) (struct rio_dev *dev, u8 swport);
+ struct rio_dev *nextdev[0];
};

/* Low-level architecture-dependent routines */
--
1.7.0.5

2010-08-13 15:20:40

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 5/9] RapidIO: Add default handler for error_stopped state

The default error-stopped state handler provides recovery mechanism as defined
by RIO specification.

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
drivers/rapidio/rio.c | 191 +++++++++++++++++++++++++++++++------
drivers/rapidio/switches/idtcps.c | 10 ++
drivers/rapidio/switches/tsi57x.c | 4 +
include/linux/rio_regs.h | 8 +-
4 files changed, 179 insertions(+), 34 deletions(-)

diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 74e9d22..f58df11 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -495,6 +495,121 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
}

/**
+ * rio_clr_err_stopped - Clears port Error-stopped states.
+ * @rdev: Pointer to RIO device control structure
+ * @pnum: Switch port number to clear errors
+ * @err_status: port error status (if 0 reads register from device)
+ */
+static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
+{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum];
+ u32 regval;
+ u32 far_ackid, far_linkstat, near_ackid;
+ int checkcount;
+
+ if (err_status == 0)
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
+ &err_status);
+
+ if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) {
+ pr_debug("RIO_EM: servicing Output Error-Stopped state\n");
+ /*
+ * Send a Link-Request/Input-Status control symbol
+ */
+
+ /* Read from link maintenance response register
+ * to clear valid bit */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
+ &regval);
+ udelay(50);
+
+ /* Issue Input-status command */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum),
+ RIO_MNT_REQ_CMD_IS);
+
+ checkcount = 3;
+ while (checkcount--) {
+ udelay(50);
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
+ &regval);
+ if (regval & RIO_PORT_N_MNT_RSP_RVAL)
+ break;
+ }
+
+ pr_debug("RIO_EM: SP%d_MNT_RSP_CSR=0x%08x\n", pnum, regval);
+ if (regval & RIO_PORT_N_MNT_RSP_RVAL) {
+ far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5;
+ far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT;
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
+ &regval);
+ pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n",
+ pnum, regval);
+ near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24;
+ pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x near_ackID=0x%02x\n",
+ pnum, far_ackid, far_linkstat, near_ackid);
+
+ /*
+ * If required, synchronize ackIDs of near and
+ * far sides.
+ */
+ if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) ||
+ (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) {
+ /* Align near outstanding/outbound ackIDs with
+ * far inbound.
+ */
+ rio_mport_write_config_32(mport, destid,
+ hopcount, rdev->phys_efptr +
+ RIO_PORT_N_ACK_STS_CSR(pnum),
+ (near_ackid << 24) |
+ (far_ackid << 8) | far_ackid);
+ /* Align far outstanding/outbound ackIDs with
+ * near inbound.
+ */
+ far_ackid++;
+ if (nextdev)
+ rio_write_config_32(nextdev,
+ nextdev->phys_efptr +
+ RIO_PORT_N_ACK_STS_CSR(nextdev->rswitch->inport),
+ (far_ackid << 24) |
+ (near_ackid << 8) | near_ackid);
+ else
+ pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n");
+ }
+ }
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
+ &err_status);
+ pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
+ }
+
+ if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) {
+ pr_debug("RIO_EM: servicing Input Error-Stopped state\n");
+ rio_write_config_32(nextdev,
+ nextdev->phys_efptr +
+ RIO_PORT_N_MNT_REQ_CSR(nextdev->rswitch->inport),
+ RIO_MNT_REQ_CMD_IS);
+ udelay(50);
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
+ &err_status);
+ pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
+ }
+
+ return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
+ RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0;
+}
+
+/**
* rio_inb_pwrite_handler - process inbound port-write message
* @pw_msg: pointer to inbound port-write message
*
@@ -507,7 +622,7 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
struct rio_mport *mport;
u8 hopcount;
u16 destid;
- u32 err_status;
+ u32 err_status, em_perrdet, em_ltlerrdet;
int rc, portnum;

rdev = rio_get_comptag(pw_msg->em.comptag, NULL);
@@ -524,12 +639,11 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
{
u32 i;
for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) {
- pr_debug("0x%02x: %08x %08x %08x %08x",
+ pr_debug("0x%02x: %08x %08x %08x %08x\n",
i*4, pw_msg->raw[i], pw_msg->raw[i + 1],
pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
i += 4;
}
- pr_debug("\n");
}
#endif

@@ -573,29 +687,28 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
&err_status);
pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);

- if (pw_msg->em.errdetect) {
- pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
- portnum, pw_msg->em.errdetect);
- /* Clear EM Port N Error Detect CSR */
- rio_mport_write_config_32(mport, destid, hopcount,
- rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
- }
+ if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {

- if (pw_msg->em.ltlerrdet) {
- pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
- pw_msg->em.ltlerrdet);
- /* Clear EM L/T Layer Error Detect CSR */
- rio_mport_write_config_32(mport, destid, hopcount,
- rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
- }
+ if (!(rdev->rswitch->port_ok & (1 << portnum))) {
+ rdev->rswitch->port_ok |= (1 << portnum);
+ rio_set_port_lockout(rdev, portnum, 0);
+ /* Schedule Insertion Service */
+ pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
+ rio_name(rdev), portnum);
+ }

- /* Clear Port Errors */
- rio_mport_write_config_32(mport, destid, hopcount,
- rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
- err_status & RIO_PORT_N_ERR_STS_CLR_MASK);
+ /* Clear error-stopped states (if reported).
+ * Depending on the link partner state, two attempts
+ * may be needed for successful recovery.
+ */
+ if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
+ RIO_PORT_N_ERR_STS_PW_INP_ES)) {
+ if (rio_clr_err_stopped(rdev, portnum, err_status))
+ rio_clr_err_stopped(rdev, portnum, 0);
+ }
+ } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */

- if (rdev->rswitch->port_ok & (1 << portnum)) {
- if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) {
+ if (rdev->rswitch->port_ok & (1 << portnum)) {
rdev->rswitch->port_ok &= ~(1 << portnum);
rio_set_port_lockout(rdev, portnum, 1);

@@ -608,17 +721,33 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n",
rio_name(rdev), portnum);
}
- } else {
- if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
- rdev->rswitch->port_ok |= (1 << portnum);
- rio_set_port_lockout(rdev, portnum, 0);
+ }

- /* Schedule Insertion Service */
- pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
- rio_name(rdev), portnum);
- }
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
+ if (em_perrdet) {
+ pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
+ portnum, em_perrdet);
+ /* Clear EM Port N Error Detect CSR */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
+ }
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
+ if (em_ltlerrdet) {
+ pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
+ em_ltlerrdet);
+ /* Clear EM L/T Layer Error Detect CSR */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
}

+ /* Clear remaining error bits */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+ err_status & RIO_PORT_N_ERR_STS_CLR_MASK);
+
/* Clear Port-Write Pending bit */
rio_mport_write_config_32(mport, destid, hopcount,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c
index 2c790c1..fc9f637 100644
--- a/drivers/rapidio/switches/idtcps.c
+++ b/drivers/rapidio/switches/idtcps.c
@@ -117,6 +117,10 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,

static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
rdev->rswitch->add_entry = idtcps_route_add_entry;
rdev->rswitch->get_entry = idtcps_route_get_entry;
@@ -126,6 +130,12 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
rdev->rswitch->em_init = NULL;
rdev->rswitch->em_handle = NULL;

+ if (do_enum) {
+ /* set TVAL = ~50us */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
+ }
+
return 0;
}

diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c
index d34df72..d9e9492 100644
--- a/drivers/rapidio/switches/tsi57x.c
+++ b/drivers/rapidio/switches/tsi57x.c
@@ -205,6 +205,10 @@ tsi57x_em_init(struct rio_dev *rdev)
portnum++;
}

+ /* set TVAL = ~50us */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8);
+
return 0;
}

diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h
index aedee04..49a4dc7 100644
--- a/include/linux/rio_regs.h
+++ b/include/linux/rio_regs.h
@@ -222,15 +222,17 @@
#define RIO_PORT_GEN_MASTER 0x40000000
#define RIO_PORT_GEN_DISCOVERED 0x20000000
#define RIO_PORT_N_MNT_REQ_CSR(x) (0x0040 + x*0x20) /* 0x0002 */
+#define RIO_MNT_REQ_CMD_RD 0x03 /* Reset-device command */
+#define RIO_MNT_REQ_CMD_IS 0x04 /* Input-status command */
#define RIO_PORT_N_MNT_RSP_CSR(x) (0x0044 + x*0x20) /* 0x0002 */
#define RIO_PORT_N_MNT_RSP_RVAL 0x80000000 /* Response Valid */
#define RIO_PORT_N_MNT_RSP_ASTAT 0x000003e0 /* ackID Status */
#define RIO_PORT_N_MNT_RSP_LSTAT 0x0000001f /* Link Status */
#define RIO_PORT_N_ACK_STS_CSR(x) (0x0048 + x*0x20) /* 0x0002 */
#define RIO_PORT_N_ACK_CLEAR 0x80000000
-#define RIO_PORT_N_ACK_INBOUND 0x1f000000
-#define RIO_PORT_N_ACK_OUTSTAND 0x00001f00
-#define RIO_PORT_N_ACK_OUTBOUND 0x0000001f
+#define RIO_PORT_N_ACK_INBOUND 0x3f000000
+#define RIO_PORT_N_ACK_OUTSTAND 0x00003f00
+#define RIO_PORT_N_ACK_OUTBOUND 0x0000003f
#define RIO_PORT_N_ERR_STS_CSR(x) (0x0058 + x*0x20)
#define RIO_PORT_N_ERR_STS_PW_OUT_ES 0x00010000 /* Output Error-stopped */
#define RIO_PORT_N_ERR_STS_PW_INP_ES 0x00000100 /* Input Error-stopped */
--
1.7.0.5

2010-08-13 15:20:30

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 3/9] RapidIO: Add the ingress port number into the RIO switch data structure

A switch ingress port number has to be saved for software assisted error
recovery from the error-stopped state. Saving this information also allows
to remove several register reads from the RIO enumeration process.

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
drivers/rapidio/rio-scan.c | 38 ++++++++------------------------------
include/linux/rio.h | 4 ++--
2 files changed, 10 insertions(+), 32 deletions(-)

diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 1123be8..efe3519 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -389,6 +389,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
int ret = 0;
struct rio_dev *rdev;
struct rio_switch *rswitch = NULL;
+ u32 swpinfo;
int result, rdid;

rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL);
@@ -440,7 +441,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
/* If a PE has both switch and other functions, show it as a switch */
if (rio_is_switch(rdev)) {
rio_mport_read_config_32(port, destid, hopcount,
- RIO_SWP_INFO_CAR, &rdev->swpinfo);
+ RIO_SWP_INFO_CAR, &swpinfo);
rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL);
if (!rswitch)
goto cleanup;
@@ -448,6 +449,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rswitch->hopcount = hopcount;
rswitch->destid = destid;
rswitch->port_ok = 0;
+ rswitch->inport = (u8)(swpinfo & RIO_SWP_INFO_PORT_NUM_MASK);
rswitch->route_table = kzalloc(sizeof(u8)*
RIO_MAX_ROUTE_ENTRIES(port->sys_size),
GFP_KERNEL);
@@ -719,25 +721,6 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)
}

/**
- * rio_get_swpinfo_inport- Gets the ingress port number
- * @mport: Master port to send transaction
- * @destid: Destination ID associated with the switch
- * @hopcount: Number of hops to the device
- *
- * Returns port number being used to access the switch device.
- */
-static u8
-rio_get_swpinfo_inport(struct rio_mport *mport, u16 destid, u8 hopcount)
-{
- u32 result;
-
- rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR,
- &result);
-
- return (u8) (result & 0xff);
-}
-
-/**
* rio_get_swpinfo_tports- Gets total number of ports on the switch
* @mport: Master port to send transaction
* @destid: Destination ID associated with the switch
@@ -834,8 +817,7 @@ static int __devinit 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(port->sys_size), hopcount);
+ sw_inport = rdev->rswitch->inport;
rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
port->host_deviceid, sw_inport, 0);
rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
@@ -989,8 +971,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
rio_name(rdev), rdev->vid, rdev->did, num_ports);
for (port_num = 0; port_num < num_ports; port_num++) {
- if (rio_get_swpinfo_inport(port, destid, hopcount) ==
- port_num)
+ if (rdev->rswitch->inport == port_num)
continue;

if (rio_sport_is_active
@@ -1092,7 +1073,6 @@ 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) {
@@ -1109,14 +1089,12 @@ static void rio_update_route_tables(struct rio_mport *port)
if (rswitch->destid == destid)
continue;

- 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, 0);
- rswitch->route_table[destid] = sport;
+ rswitch->inport, 0);
+ rswitch->route_table[destid] =
+ rswitch->inport;
}
}
}
diff --git a/include/linux/rio.h b/include/linux/rio.h
index 84c9f8c..718075a 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -86,7 +86,6 @@ union rio_pw_msg;
* @asm_rev: Assembly revision
* @efptr: Extended feature pointer
* @pef: Processing element features
- * @swpinfo: Switch port info
* @src_ops: Source operation capabilities
* @dst_ops: Destination operation capabilities
* @comp_tag: RIO component tag
@@ -112,7 +111,6 @@ struct rio_dev {
u16 asm_rev;
u16 efptr;
u32 pef;
- u32 swpinfo; /* Only used for switches */
u32 src_ops;
u32 dst_ops;
u32 comp_tag;
@@ -222,6 +220,7 @@ struct rio_net {
* @switchid: Switch ID that is unique across a network
* @hopcount: Hopcount to this switch
* @destid: Associated destid in the path
+ * @inport: Switch ingress port number
* @route_table: Copy of switch routing table
* @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0
* @add_entry: Callback for switch-specific route add function
@@ -237,6 +236,7 @@ struct rio_switch {
u16 switchid;
u16 hopcount;
u16 destid;
+ u8 inport;
u8 *route_table;
u32 port_ok;
int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
--
1.7.0.5

2010-08-13 15:20:16

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 1/9] RapidIO: fix RapidIO sysfs hierarchy

Makes RapidIO devices appear in /sys/devices/rapidio directory instead of top
of /sys/devices directory.

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
drivers/rapidio/rio-driver.c | 2 +-
drivers/rapidio/rio-scan.c | 1 +
include/linux/rio.h | 1 +
3 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index 3222fa3..0f4a53b 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -192,7 +192,7 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv)
out:return 0;
}

-static struct device rio_bus = {
+struct device rio_bus = {
.init_name = "rapidio",
};

diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 8070e07..1123be8 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -478,6 +478,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
}

rdev->dev.bus = &rio_bus_type;
+ rdev->dev.parent = &rio_bus;

device_initialize(&rdev->dev);
rdev->dev.release = rio_release_dev;
diff --git a/include/linux/rio.h b/include/linux/rio.h
index bd6eb0e..84c9f8c 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -67,6 +67,7 @@
#define RIO_PW_MSG_SIZE 64

extern struct bus_type rio_bus_type;
+extern struct device rio_bus;
extern struct list_head rio_devices; /* list of all devices */

struct rio_mport;
--
1.7.0.5

2010-08-13 15:20:50

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 7/9] RapidIO: Add handling for PW message from a lost device

Add check if PW message source device is accessible and change PW message
handler to recover if PW message source device is not available anymore (power
down or link disconnect).
To avoid possible loss of notification, the PW message handler scans the route
back from the source device to identify end of the broken link.

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
drivers/rapidio/rio.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++--
drivers/rapidio/rio.h | 2 +
2 files changed, 108 insertions(+), 5 deletions(-)

diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index f58df11..22f7847 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -495,6 +495,90 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
}

/**
+ * rio_chk_dev_route - Validate route to the specified device.
+ * @rdev: Pointer to RIO device control structure
+ * @nrdev: Pointer to last active device on the route to rdev
+ * @npnum: nrdev port number on the route to rdev
+ *
+ * Follows a route to the specified RIO device to determine the last available
+ * device (and corresponding RIO port) on the route.
+ */
+static int
+rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum)
+{
+ u32 result;
+ int p_port, rc = -EIO;
+ struct rio_dev *prev = NULL;
+
+ while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) {
+ if (rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) {
+ rdev = rdev->prev;
+ continue;
+ }
+
+ prev = rdev->prev;
+ for (p_port = 0; p_port < prev->rswitch->nports; p_port++)
+ if (prev->rswitch->nextdev[p_port] == rdev)
+ break;
+
+ if (p_port < prev->rswitch->nports) {
+ pr_debug("RIO: link failed on [%s]-P%d\n",
+ rio_name(prev), p_port);
+ *nrdev = prev;
+ *npnum = p_port;
+ rc = 0;
+ } else {
+ pr_debug("RIO: failed to trace route to %s\n",
+ rio_name(prev));
+ }
+
+ break;
+ }
+
+ return rc;
+}
+
+/**
+ * rio_mport_chk_dev_access - Validate access to the specified device.
+ * @mport: Master port to send transactions
+ * @destid: Device destination ID in network
+ * @hopcount: Number of hops into the network
+ */
+static int
+rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount)
+{
+ int i = 0;
+ u32 tmp;
+
+ while (rio_mport_read_config_32(mport, destid, hopcount,
+ RIO_DEV_ID_CAR, &tmp)) {
+ i++;
+ if (i == RIO_MAX_CHK_RETRY)
+ return -EIO;
+ mdelay(1);
+ }
+
+ return 0;
+}
+
+/**
+ * rio_chk_dev_access - Validate access to the specified device.
+ * @rdev: Pointer to RIO device control structure
+ */
+static int rio_chk_dev_access(struct rio_dev *rdev)
+{
+ u8 hopcount = 0xff;
+ u16 destid = rdev->destid;
+
+ if (rdev->rswitch) {
+ destid = rdev->rswitch->destid;
+ hopcount = rdev->rswitch->hopcount;
+ }
+
+ return rio_mport_chk_dev_access(rdev->net->hport, destid, hopcount);
+}
+
+/**
* rio_clr_err_stopped - Clears port Error-stopped states.
* @rdev: Pointer to RIO device control structure
* @pnum: Switch port number to clear errors
@@ -627,8 +711,8 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)

rdev = rio_get_comptag(pw_msg->em.comptag, NULL);
if (rdev == NULL) {
- /* Someting bad here (probably enumeration error) */
- pr_err("RIO: %s No matching device for CTag 0x%08x\n",
+ /* Device removed or enumeration error */
+ pr_debug("RIO: %s No matching device for CTag 0x%08x\n",
__func__, pw_msg->em.comptag);
return -EIO;
}
@@ -659,6 +743,26 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
return 0;
}

+ portnum = pw_msg->em.is_port & 0xFF;
+
+ /* Check if device and route to it are functional:
+ * Sometimes devices may send PW message(s) just before being
+ * powered down (or link being lost).
+ */
+ if (rio_chk_dev_access(rdev)) {
+ pr_debug("RIO: device access failed - get link partner\n");
+ /* Scan route to the device and identify failed link.
+ * This will replace device and port reported in PW message.
+ * PW message should not be used after this point.
+ */
+ if (rio_chk_dev_route(rdev, &rdev, &portnum)) {
+ pr_err("RIO: Route trace for %s failed\n",
+ rio_name(rdev));
+ return -EIO;
+ }
+ pw_msg = NULL;
+ }
+
/* For End-point devices processing stops here */
if (!(rdev->pef & RIO_PEF_SWITCH))
return 0;
@@ -676,9 +780,6 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
/*
* Process the port-write notification from switch
*/
-
- portnum = pw_msg->em.is_port & 0xFF;
-
if (rdev->rswitch->em_handle)
rdev->rswitch->em_handle(rdev, portnum);

diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index f27b7a9..bc71ba1 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -14,6 +14,8 @@
#include <linux/list.h>
#include <linux/rio.h>

+#define RIO_MAX_CHK_RETRY 3
+
/* Functions internal to the RIO core code */

extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid,
--
1.7.0.5

2010-08-13 15:20:46

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 6/9] RapidIO: Add switch-specific sysfs initialization callback

Add callback that allows to create/remove switch-specific sysfs attributes.

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
drivers/rapidio/rio-sysfs.c | 26 +++++++++++++++++++-------
include/linux/rio.h | 2 ++
2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 00b4756..bfc483b 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -40,9 +40,6 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
char *str = buf;
int i;

- if (!rdev->rswitch)
- goto out;
-
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
i++) {
if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE)
@@ -52,7 +49,6 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
rdev->rswitch->route_table[i]);
}

- out:
return (str - buf);
}

@@ -63,10 +59,11 @@ struct device_attribute rio_dev_attrs[] = {
__ATTR_RO(asm_did),
__ATTR_RO(asm_vid),
__ATTR_RO(asm_rev),
- __ATTR_RO(routes),
__ATTR_NULL,
};

+static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
+
static ssize_t
rio_read_config(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
@@ -218,7 +215,17 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
{
int err = 0;

- err = sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr);
+ err = device_create_bin_file(&rdev->dev, &rio_config_attr);
+
+ if (!err && rdev->rswitch) {
+ err = device_create_file(&rdev->dev, &dev_attr_routes);
+ if (!err && rdev->rswitch->sw_sysfs)
+ err = rdev->rswitch->sw_sysfs(rdev, 1);
+ }
+
+ if (err)
+ pr_warning("RIO: Failed to create attribute file(s) for %s\n",
+ rio_name(rdev));

return err;
}
@@ -231,5 +238,10 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
*/
void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
{
- sysfs_remove_bin_file(&rdev->dev.kobj, &rio_config_attr);
+ device_remove_bin_file(&rdev->dev, &rio_config_attr);
+ if (rdev->rswitch) {
+ device_remove_file(&rdev->dev, &dev_attr_routes);
+ if (rdev->rswitch->sw_sysfs)
+ rdev->rswitch->sw_sysfs(rdev, 0);
+ }
}
diff --git a/include/linux/rio.h b/include/linux/rio.h
index 754895c..8f19fb2 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -233,6 +233,7 @@ struct rio_net {
* @get_domain: Callback for switch-specific domain get function
* @em_init: Callback for switch-specific error management initialization function
* @em_handle: Callback for switch-specific error management handler function
+ * @sw_sysfs: Callback that initializes switch-specific sysfs attributes
* @nextdev: Array of per-port pointers to the next attached device
*/
struct rio_switch {
@@ -256,6 +257,7 @@ struct rio_switch {
u8 *sw_domain);
int (*em_init) (struct rio_dev *dev);
int (*em_handle) (struct rio_dev *dev, u8 swport);
+ int (*sw_sysfs) (struct rio_dev *dev, int create);
struct rio_dev *nextdev[0];
};

--
1.7.0.5

2010-08-13 15:21:43

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 2/9] RapidIO,powerpc/85xx: modify RIO port-write interrupt handler

- Rearranged RIO port-write interrupt handling to perform message buffering
as soon as possible.
- Modified to disable port-write controller when clearing Transaction Error (TE)
bit.

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
arch/powerpc/sysdev/fsl_rio.c | 67 ++++++++++++++++++++++------------------
1 files changed, 37 insertions(+), 30 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index cd71dc1..708d94e 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -1065,18 +1065,12 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
struct rio_priv *priv = port->priv;
u32 epwisr, tmp;

- ipwmr = in_be32(&priv->msg_regs->pwmr);
- ipwsr = in_be32(&priv->msg_regs->pwsr);
-
epwisr = in_be32(priv->regs_win + RIO_EPWISR);
- if (epwisr & 0x80000000) {
- tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
- pr_info("RIO_LTLEDCSR = 0x%x\n", tmp);
- out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
- }
-
if (!(epwisr & 0x00000001))
- return IRQ_HANDLED;
+ goto pw_done;
+
+ ipwmr = in_be32(&priv->msg_regs->pwmr);
+ ipwsr = in_be32(&priv->msg_regs->pwsr);

#ifdef DEBUG_PW
pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
@@ -1092,22 +1086,8 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
pr_debug(" PWB");
pr_debug(" )\n");
#endif
- out_be32(&priv->msg_regs->pwsr,
- ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
-
- if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
- priv->port_write_msg.err_count++;
- pr_info("RIO: Port-Write Transaction Err (%d)\n",
- priv->port_write_msg.err_count);
- }
- if (ipwsr & RIO_IPWSR_PWD) {
- priv->port_write_msg.discard_count++;
- pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
- priv->port_write_msg.discard_count);
- }
-
/* Schedule deferred processing if PW was received */
- if (ipwsr & RIO_IPWSR_QFI) {
+ if ((ipwmr & RIO_IPWMR_QFIE) && (ipwsr & RIO_IPWSR_QFI)) {
/* Save PW message (if there is room in FIFO),
* otherwise discard it.
*/
@@ -1117,16 +1097,43 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
RIO_PW_MSG_SIZE);
} else {
priv->port_write_msg.discard_count++;
- pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
+ pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
priv->port_write_msg.discard_count);
}
+ /* Clear interrupt and issue Clear Queue command. This allows
+ * another port-write to be received.
+ */
+ out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_QFI);
+ out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+
schedule_work(&priv->pw_work);
}

- /* Issue Clear Queue command. This allows another
- * port-write to be received.
- */
- out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+ if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
+ priv->port_write_msg.err_count++;
+ pr_debug("RIO: Port-Write Transaction Err (%d)\n",
+ priv->port_write_msg.err_count);
+ /* Clear Transaction Error: port-write controller should be
+ * disabled when clearing this error
+ */
+ out_be32(&priv->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
+ out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_TE);
+ out_be32(&priv->msg_regs->pwmr, ipwmr);
+ }
+
+ if (ipwsr & RIO_IPWSR_PWD) {
+ priv->port_write_msg.discard_count++;
+ pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
+ priv->port_write_msg.discard_count);
+ out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_PWD);
+ }
+
+pw_done:
+ if (epwisr & 0x80000000) {
+ tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+ out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+ }

return IRQ_HANDLED;
}
--
1.7.0.5

2010-08-13 15:22:48

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 8/9] RapidIO: Add device access check into the enumeration

Add explicit device access check before performing device enumeration.
This gives a chance to clear possible link error conditions by issuing safe
maintenance read request(s).

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
drivers/rapidio/rio-scan.c | 6 ++++++
drivers/rapidio/rio.c | 2 +-
drivers/rapidio/rio.h | 2 ++
3 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 5dc33d1..fb5324b 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -761,6 +761,12 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
u16 destid;
int tmp;

+ if (rio_mport_chk_dev_access(port,
+ RIO_ANY_DESTID(port->sys_size), hopcount)) {
+ pr_debug("RIO: device access check failed\n");
+ return -1;
+ }
+
if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) {
pr_debug("RIO: PE already discovered by this host\n");
/*
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 22f7847..9621a7b 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -544,7 +544,7 @@ rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum)
* @destid: Device destination ID in network
* @hopcount: Number of hops into the network
*/
-static int
+int
rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount)
{
int i = 0;
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index bc71ba1..d249a12 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -24,6 +24,8 @@ extern u32 rio_mport_get_physefb(struct rio_mport *port, int local,
u16 destid, u8 hopcount);
extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
u8 hopcount, u32 from);
+extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid,
+ u8 hopcount);
extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
extern int rio_enum_mport(struct rio_mport *mport);
extern int rio_disc_mport(struct rio_mport *mport);
--
1.7.0.5

2010-08-13 15:39:16

by Bounine, Alexandre

[permalink] [raw]
Subject: [PATCH 9/9] RapidIO: Add support for IDT CPS Gen2 switches

Add the RIO switch driver and definitions for IDT CPS-1848 and CPS-1616 Gen2
devices.

Signed-off-by: Alexandre Bounine <[email protected]>
Reviewed-by: Thomas Moll <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Li Yang <[email protected]>
Cc: Kumar Gala <[email protected]>
---
drivers/rapidio/switches/Kconfig | 7 +
drivers/rapidio/switches/Makefile | 1 +
drivers/rapidio/switches/idt_gen2.c | 439 +++++++++++++++++++++++++++++++++++
include/linux/rio_ids.h | 2 +
include/linux/rio_regs.h | 4 +
5 files changed, 453 insertions(+), 0 deletions(-)
create mode 100644 drivers/rapidio/switches/idt_gen2.c

diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig
index 2b4e9b2..f47fee5 100644
--- a/drivers/rapidio/switches/Kconfig
+++ b/drivers/rapidio/switches/Kconfig
@@ -20,6 +20,13 @@ config RAPIDIO_TSI568
---help---
Includes support for IDT Tsi568 serial RapidIO switch.

+config RAPIDIO_CPS_GEN2
+ bool "IDT CPS Gen.2 SRIO switch support"
+ depends on RAPIDIO
+ default n
+ ---help---
+ Includes support for ITD CPS Gen.2 serial RapidIO switches.
+
config RAPIDIO_TSI500
bool "Tsi500 Parallel RapidIO switch support"
depends on RAPIDIO
diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile
index fe4adc3..48d67a6 100644
--- a/drivers/rapidio/switches/Makefile
+++ b/drivers/rapidio/switches/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_RAPIDIO_TSI57X) += tsi57x.o
obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o
obj-$(CONFIG_RAPIDIO_TSI568) += tsi568.o
obj-$(CONFIG_RAPIDIO_TSI500) += tsi500.o
+obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o

ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c
new file mode 100644
index 0000000..0de4a9c
--- /dev/null
+++ b/drivers/rapidio/switches/idt_gen2.c
@@ -0,0 +1,439 @@
+/*
+ * IDT CPS Gen.2 Serial RapidIO switch family support
+ *
+ * Copyright 2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+#include "../rio.h"
+
+#define LOCAL_RTE_CONF_DESTID_SEL 0x010070
+#define LOCAL_RTE_CONF_DESTID_SEL_PSEL 0x0000001f
+
+#define IDT_LT_ERR_REPORT_EN 0x03100c
+
+#define IDT_PORT_ERR_REPORT_EN(n) (0x031044 + (n)*0x40)
+#define IDT_PORT_ERR_REPORT_EN_BC 0x03ff04
+
+#define IDT_PORT_ISERR_REPORT_EN(n) (0x03104C + (n)*0x40)
+#define IDT_PORT_ISERR_REPORT_EN_BC 0x03ff0c
+#define IDT_PORT_INIT_TX_ACQUIRED 0x00000020
+
+#define IDT_LANE_ERR_REPORT_EN(n) (0x038010 + (n)*0x100)
+#define IDT_LANE_ERR_REPORT_EN_BC 0x03ff10
+
+#define IDT_DEV_CTRL_1 0xf2000c
+#define IDT_DEV_CTRL_1_GENPW 0x02000000
+#define IDT_DEV_CTRL_1_PRSTBEH 0x00000001
+
+#define IDT_CFGBLK_ERR_CAPTURE_EN 0x020008
+#define IDT_CFGBLK_ERR_REPORT 0xf20014
+#define IDT_CFGBLK_ERR_REPORT_GENPW 0x00000002
+
+#define IDT_AUX_PORT_ERR_CAP_EN 0x020000
+#define IDT_AUX_ERR_REPORT_EN 0xf20018
+#define IDT_AUX_PORT_ERR_LOG_I2C 0x00000002
+#define IDT_AUX_PORT_ERR_LOG_JTAG 0x00000001
+
+#define IDT_ISLTL_ADDRESS_CAP 0x021014
+
+#define IDT_RIO_DOMAIN 0xf20020
+#define IDT_RIO_DOMAIN_MASK 0x000000ff
+
+#define IDT_PW_INFO_CSR 0xf20024
+
+#define IDT_SOFT_RESET 0xf20040
+#define IDT_SOFT_RESET_REQ 0x00030097
+
+#define IDT_I2C_MCTRL 0xf20050
+#define IDT_I2C_MCTRL_GENPW 0x04000000
+
+#define IDT_JTAG_CTRL 0xf2005c
+#define IDT_JTAG_CTRL_GENPW 0x00000002
+
+#define IDT_LANE_CTRL(n) (0xff8000 + (n)*0x100)
+#define IDT_LANE_CTRL_BC 0xffff00
+#define IDT_LANE_CTRL_GENPW 0x00200000
+#define IDT_LANE_DFE_1_BC 0xffff18
+#define IDT_LANE_DFE_2_BC 0xffff1c
+
+#define IDT_PORT_OPS(n) (0xf40004 + (n)*0x100)
+#define IDT_PORT_OPS_GENPW 0x08000000
+#define IDT_PORT_OPS_PL_ELOG 0x00000040
+#define IDT_PORT_OPS_LL_ELOG 0x00000020
+#define IDT_PORT_OPS_LT_ELOG 0x00000010
+#define IDT_PORT_OPS_BC 0xf4ff04
+
+#define IDT_PORT_ISERR_DET(n) (0xf40008 + (n)*0x100)
+
+#define IDT_ERR_CAP 0xfd0000
+#define IDT_ERR_CAP_LOG_OVERWR 0x00000004
+
+#define IDT_ERR_RD 0xfd0004
+
+#define IDT_DEFAULT_ROUTE 0xde
+#define IDT_NO_ROUTE 0xdf
+
+static int
+idtg2_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table, u16 route_destid, u8 route_port)
+{
+ /*
+ * Select routing table to update
+ */
+ if (table == RIO_GLOBAL_TABLE)
+ table = 0;
+ else
+ table++;
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ LOCAL_RTE_CONF_DESTID_SEL, table);
+
+ /*
+ * Program destination port for the specified destID
+ */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+ (u32)route_destid);
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_PORT_SEL_CSR,
+ (u32)route_port);
+
+ return 0;
+}
+
+static int
+idtg2_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table, u16 route_destid, u8 *route_port)
+{
+ u32 result;
+
+ /*
+ * Select routing table to read
+ */
+ if (table == RIO_GLOBAL_TABLE)
+ table = 0;
+ else
+ table++;
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ LOCAL_RTE_CONF_DESTID_SEL, table);
+
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+ route_destid);
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+ if (IDT_DEFAULT_ROUTE == (u8)result || IDT_NO_ROUTE == (u8)result)
+ *route_port = RIO_INVALID_ROUTE;
+ else
+ *route_port = (u8)result;
+
+
+ return 0;
+}
+
+static int
+idtg2_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table)
+{
+ u32 i;
+
+ /*
+ * Select routing table to read
+ */
+ if (table == RIO_GLOBAL_TABLE)
+ table = 0;
+ else
+ table++;
+
+ rio_mport_write_config_32(mport, destid, hopcount,
+ LOCAL_RTE_CONF_DESTID_SEL, table);
+
+ for (i = 0x80000000; i <= 0x800000ff;) {
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ RIO_STD_RTE_CONF_PORT_SEL_CSR,
+ (IDT_DEFAULT_ROUTE << 24) | (IDT_DEFAULT_ROUTE << 16) |
+ (IDT_DEFAULT_ROUTE << 8) | IDT_DEFAULT_ROUTE);
+ i += 4;
+ }
+
+ return 0;
+}
+
+
+static int
+idtg2_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u8 sw_domain)
+{
+ /*
+ * Switch domain configuration operates only at global level
+ */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_RIO_DOMAIN, (u32)sw_domain);
+ return 0;
+}
+
+static int
+idtg2_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u8 *sw_domain)
+{
+ u32 regval;
+
+ /*
+ * Switch domain configuration operates only at global level
+ */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_RIO_DOMAIN, &regval);
+
+ *sw_domain = (u8)(regval & 0xff);
+
+ return 0;
+}
+
+static int
+idtg2_em_init(struct rio_dev *rdev)
+{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ u32 regval;
+
+ /*
+ * This routine performs device-specific initialization only.
+ * All standard EM configuration should be performed at upper level.
+ */
+
+ pr_debug("RIO: %s [%d:%d]\n", __func__, destid, hopcount);
+
+ /* Set Port-Write info CSR: PRIO=3 and CRF=1 */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PW_INFO_CSR, 0x0000e000);
+
+ /*
+ * Configure LT LAYER error reporting.
+ */
+
+ /* Enable standard (RIO.p8) error reporting */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_LT_ERR_REPORT_EN,
+ REM_LTL_ERR_ILLTRAN | REM_LTL_ERR_UNSOLR |
+ REM_LTL_ERR_UNSUPTR);
+
+ /* Use Port-Writes for LT layer error reporting.
+ * Enable per-port reset
+ */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_DEV_CTRL_1, &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_DEV_CTRL_1,
+ regval | IDT_DEV_CTRL_1_GENPW | IDT_DEV_CTRL_1_PRSTBEH);
+
+ /*
+ * Configure PORT error reporting.
+ */
+
+ /* Report all RIO.p8 errors supported by device */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037);
+
+ /* Configure repoting of implementation specific errors/events */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PORT_ISERR_REPORT_EN_BC, IDT_PORT_INIT_TX_ACQUIRED);
+
+ /* Use Port-Writes for port error reporting and enable error logging */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_PORT_OPS_BC, &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PORT_OPS_BC, regval | IDT_PORT_OPS_GENPW |
+ IDT_PORT_OPS_PL_ELOG |
+ IDT_PORT_OPS_LL_ELOG |
+ IDT_PORT_OPS_LT_ELOG);
+ /* Overwrite error log if full */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR);
+
+ /*
+ * Configure LANE error reporting.
+ */
+
+ /* Disable line error reporting */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_LANE_ERR_REPORT_EN_BC, 0);
+
+ /* Use Port-Writes for lane error reporting (when enabled) */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_LANE_CTRL_BC, &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_LANE_CTRL_BC, regval | IDT_LANE_CTRL_GENPW);
+
+ /*
+ * Configure AUX error reporting.
+ */
+
+ /* Disable JTAG and I2C Error capture */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_AUX_PORT_ERR_CAP_EN, 0);
+
+ /* Disable JTAG and I2C Error reporting/logging */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_AUX_ERR_REPORT_EN, 0);
+
+ /* Disable Port-Write notification from JTAG */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_JTAG_CTRL, 0);
+
+ /* Disable Port-Write notification from I2C */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_I2C_MCTRL, &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_I2C_MCTRL,
+ regval & ~IDT_I2C_MCTRL_GENPW);
+
+ /*
+ * Configure CFG_BLK error reporting.
+ */
+
+ /* Disable Configuration Block error capture */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_CFGBLK_ERR_CAPTURE_EN, 0);
+
+ /* Disable Port-Writes for Configuration Block error reporting */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_CFGBLK_ERR_REPORT, &regval);
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_CFGBLK_ERR_REPORT,
+ regval & ~IDT_CFGBLK_ERR_REPORT_GENPW);
+
+ /* set TVAL = ~50us */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
+
+ return 0;
+}
+
+static int
+idtg2_em_handler(struct rio_dev *rdev, u8 portnum)
+{
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ u32 regval, em_perrdet, em_ltlerrdet;
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
+ if (em_ltlerrdet) {
+ /* Service Logical/Transport Layer Error(s) */
+ if (em_ltlerrdet & REM_LTL_ERR_IMPSPEC) {
+ /* Implementation specific error reported */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_ISLTL_ADDRESS_CAP, &regval);
+
+ pr_debug("RIO: %s Implementation Specific LTL errors" \
+ " 0x%x @(0x%x)\n",
+ rio_name(rdev), em_ltlerrdet, regval);
+
+ /* Clear implementation specific address capture CSR */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_ISLTL_ADDRESS_CAP, 0);
+
+ }
+ }
+
+ rio_mport_read_config_32(mport, destid, hopcount,
+ rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
+ if (em_perrdet) {
+ /* Service Port-Level Error(s) */
+ if (em_perrdet & REM_PED_IMPL_SPEC) {
+ /* Implementation Specific port error reported */
+
+ /* Get IS errors reported */
+ rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_PORT_ISERR_DET(portnum), &regval);
+
+ pr_debug("RIO: %s Implementation Specific Port" \
+ " errors 0x%x\n", rio_name(rdev), regval);
+
+ /* Clear all implementation specific events */
+ rio_mport_write_config_32(mport, destid, hopcount,
+ IDT_PORT_ISERR_DET(portnum), 0);
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t
+idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct rio_dev *rdev = to_rio_dev(dev);
+ struct rio_mport *mport = rdev->net->hport;
+ u16 destid = rdev->rswitch->destid;
+ u8 hopcount = rdev->rswitch->hopcount;
+ ssize_t len = 0;
+ u32 regval;
+
+ while (!rio_mport_read_config_32(mport, destid, hopcount,
+ IDT_ERR_RD, &regval)) {
+ if (!regval) /* 0 = end of log */
+ break;
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%08x\n", regval);
+ if (len >= (PAGE_SIZE - 10))
+ break;
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(errlog, S_IRUGO, idtg2_show_errlog, NULL);
+
+static int idtg2_sysfs(struct rio_dev *rdev, int create)
+{
+ struct device *dev = &rdev->dev;
+ int err = 0;
+
+ if (create) {
+ /* Initialize sysfs entries */
+ err = device_create_file(dev, &dev_attr_errlog);
+ if (err)
+ dev_err(dev, "Unable create sysfs errlog file\n");
+ } else
+ device_remove_file(dev, &dev_attr_errlog);
+
+
+ return err;
+}
+
+static int idtg2_switch_init(struct rio_dev *rdev, int do_enum)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ rdev->rswitch->add_entry = idtg2_route_add_entry;
+ rdev->rswitch->get_entry = idtg2_route_get_entry;
+ rdev->rswitch->clr_table = idtg2_route_clr_table;
+ rdev->rswitch->set_domain = idtg2_set_domain;
+ rdev->rswitch->get_domain = idtg2_get_domain;
+ rdev->rswitch->em_init = idtg2_em_init;
+ rdev->rswitch->em_handle = idtg2_em_handler;
+ rdev->rswitch->sw_sysfs = idtg2_sysfs;
+
+ return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init);
diff --git a/include/linux/rio_ids.h b/include/linux/rio_ids.h
index db50e1c..ee7b6ad 100644
--- a/include/linux/rio_ids.h
+++ b/include/linux/rio_ids.h
@@ -34,5 +34,7 @@
#define RIO_DID_IDTCPS16 0x035b
#define RIO_DID_IDTCPS6Q 0x035f
#define RIO_DID_IDTCPS10Q 0x035e
+#define RIO_DID_IDTCPS1848 0x0374
+#define RIO_DID_IDTCPS1616 0x0379

#endif /* LINUX_RIO_IDS_H */
diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h
index 49a4dc7..7f98fb6 100644
--- a/include/linux/rio_regs.h
+++ b/include/linux/rio_regs.h
@@ -263,6 +263,10 @@
#define RIO_EM_EFB_HEADER 0x000 /* Error Management Extensions Block Header */
#define RIO_EM_LTL_ERR_DETECT 0x008 /* Logical/Transport Layer Error Detect CSR */
#define RIO_EM_LTL_ERR_EN 0x00c /* Logical/Transport Layer Error Enable CSR */
+#define REM_LTL_ERR_ILLTRAN 0x08000000 /* Illegal Transaction decode */
+#define REM_LTL_ERR_UNSOLR 0x00800000 /* Unsolicited Response */
+#define REM_LTL_ERR_UNSUPTR 0x00400000 /* Unsupported Transaction */
+#define REM_LTL_ERR_IMPSPEC 0x000000ff /* Implementation Specific */
#define RIO_EM_LTL_HIADDR_CAP 0x010 /* Logical/Transport Layer High Address Capture CSR */
#define RIO_EM_LTL_ADDR_CAP 0x014 /* Logical/Transport Layer Address Capture CSR */
#define RIO_EM_LTL_DEVID_CAP 0x018 /* Logical/Transport Layer Device ID Capture CSR */
--
1.7.0.5

2010-08-16 12:12:55

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 2/9] RapidIO, powerpc/85xx: modify RIO port-write interrupt handler

Alexandre Bounine wrote:
> - Rearranged RIO port-write interrupt handling to perform message buffering
> as soon as possible.

I don't understand this comment: you still schedule work to read the
port-write queue; so how is this message buffering performed as soon as
possible?

> - Modified to disable port-write controller when clearing Transaction Error (TE)
> bit.
> /* Schedule deferred processing if PW was received */
> - if (ipwsr & RIO_IPWSR_QFI) {
> + if ((ipwmr & RIO_IPWMR_QFIE) && (ipwsr & RIO_IPWSR_QFI)) {

Why check the QFIE bit also?

> +pw_done:
> + if (epwisr & 0x80000000) {

Magic value.

Micha

2010-08-16 12:14:55

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 3/9] RapidIO: Add the ingress port number into the RIO switch data structure

Alexandre Bounine wrote:
> A switch ingress port number has to be saved for software assisted error
> recovery from the error-stopped state. Saving this information also allows
> to remove several register reads from the RIO enumeration process.

Why not keep using the swpinfo field, as you can extract it from there?
And your code actually does this.

Also processor devices can have multiple ports (not only switches), it
would be good to be ready for that use case.

Micha

2010-08-16 12:18:41

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 4/9] RapidIO: Add relation links between RIO device structures

Alexandre Bounine wrote:
> Create back and forward links between RIO devices. These links are intended for
> use by error management and hot-plug extensions.

As RapidIO is a switched network, the concept of 'previous' and 'next'
devices is invalid. Perhaps it's just the way they were
discovered/enumerated, but that does not matter any more at runtime. Or
at least, should not matter.

> @@ -237,6 +241,7 @@ struct rio_switch {
> u16 hopcount;
> u16 destid;
> u8 inport;
> + u8 nports;
> u8 *route_table;
> u32 port_ok;

This can be extracted from the swpinfo field (which you removed in
another patch)?

Micha

2010-08-16 12:21:37

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 5/9] RapidIO: Add default handler for error_stopped state

Alexandre Bounine wrote:
> +
> + if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) {
> + pr_debug("RIO_EM: servicing Output Error-Stopped state\n");
> + /*
> + * Send a Link-Request/Input-Status control symbol
> + */
> +
> + /* Read from link maintenance response register
> + * to clear valid bit */
> + rio_mport_read_config_32(mport, destid, hopcount,
> + rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
> + &regval);
> + udelay(50);

Perhaps this whole part of operating the MNT_RSP registers (sending
link-request symbol is the only useful action IIRC?) can be put in a
separate function for readability.

Micha

2010-08-16 12:25:52

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 6/9] RapidIO: Add switch-specific sysfs initialization callback

Alexandre Bounine wrote:
> - if (!rdev->rswitch)
> - goto out;
> -

Is it safe? All devices have a switch?

> @@ -63,10 +59,11 @@ struct device_attribute rio_dev_attrs[] = {
> __ATTR_RO(asm_did),
> __ATTR_RO(asm_vid),
> __ATTR_RO(asm_rev),
> - __ATTR_RO(routes),
> __ATTR_NULL,
> };
>
> +static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
> +

This seems a separate change from the sw_sysfs? Why make it separate?

> */
> struct rio_switch {
> @@ -256,6 +257,7 @@ struct rio_switch {
> u8 *sw_domain);
> int (*em_init) (struct rio_dev *dev);
> int (*em_handle) (struct rio_dev *dev, u8 swport);
> + int (*sw_sysfs) (struct rio_dev *dev, int create);
> struct rio_dev *nextdev[0];
> };

Why not make a sw_sysfs_create and sw_sysfs_remove? Is better for
readability. Now you call 'sw_sysfs(dev, 0)' or 'sw_sysfs(dev, 1)';

Micha

2010-08-16 12:29:40

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 7/9] RapidIO: Add handling for PW message from a lost device

Alexandre Bounine wrote:
> Add check if PW message source device is accessible and change PW message
> handler to recover if PW message source device is not available anymore (power
> down or link disconnect).

I am not quite sure what the point is of this patch. What do you need to
recover from?

> To avoid possible loss of notification, the PW message handler scans the route
> back from the source device to identify end of the broken link.

Do you mean if port-writes are dropped? Then they did not reach you in
the first place. If a link in between is broken, the associated switch
will 'complain' and send port-writes, no?

Micha

2010-08-16 12:30:58

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 0/9] RapidIO: Set of patches to add Gen2 switches

Alexandre Bounine wrote:
> This set of RapidIO patches adds support for new IDT Gen2 sRIO switch
> devices - CPS-1848 and CPS-1616.
> Adding these sRIO switches required to implement standard error recovery
> mechanism defined by the RapidIO specification.

This is not 'Gen2' specific, as these error management extensions also
exist in v1.2/1.3 (?) of the specification? E.g. tsi56x and tsi57x could
support this functionality?

Micha

2010-08-16 12:37:04

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 9/9] RapidIO: Add support for IDT CPS Gen2 switches

Alexandre Bounine wrote:
> + rio_mport_write_config_32(mport, destid, hopcount,
> + LOCAL_RTE_CONF_DESTID_SEL, table);
> +
> + for (i = 0x80000000; i <= 0x800000ff;) {
> + rio_mport_write_config_32(mport, destid, hopcount,
> + RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);

The 0x80000000 is that an autoincrement bit? If so, it only needs to do
this once I think? If so please call it like that, and loop the 'i'
variable through the destination IDs.

Micha

2010-08-16 13:42:44

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 3/9] RapidIO: Add the ingress port number into the RIO switch data structure

Micha Nelissen wrote:
>
> Alexandre Bounine wrote:
> > A switch ingress port number has to be saved for software assisted
error
> > recovery from the error-stopped state. Saving this information also
allows
> > to remove several register reads from the RIO enumeration process.
>
> Why not keep using the swpinfo field, as you can extract it from
there?
> And your code actually does this.
>
> Also processor devices can have multiple ports (not only switches), it
> would be good to be ready for that use case.
>
Agree. I missed the Multiport bit introduced in RIO spec 2.1. Now it is
justified to be as it was before.
I will rework this and next patches.

2010-08-16 14:02:27

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 4/9] RapidIO: Add relation links between RIO device structures

Micha Nelissen wrote:
>
> Alexandre Bounine wrote:
> > Create back and forward links between RIO devices. These links are
intended for
> > use by error management and hot-plug extensions.
>
> As RapidIO is a switched network, the concept of 'previous' and 'next'
> devices is invalid. Perhaps it's just the way they were
> discovered/enumerated, but that does not matter any more at runtime.
Or
> at least, should not matter.
>

Yes, the "previous" and "next" have to be considered in context of
enumeration/discovery.
At runtime, it does not matter for data traffic, but is valuable
information for error recovery
And hot-swap. This provides snapshot of device connections. For example,
when servicing
error-stopped state of link between two switches you need to know
ingress port of far switch on
the link. It may be a problem to read it directly from the device.
Searching through the device list
becomes time consuming as a system size grows.

> > @@ -237,6 +241,7 @@ struct rio_switch {
> > u16 hopcount;
> > u16 destid;
> > u8 inport;
> > + u8 nports;
> > u8 *route_table;
> > u32 port_ok;
>
> This can be extracted from the swpinfo field (which you removed in
> another patch)?
>
Agreed in response for patch #3

2010-08-16 14:47:51

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 5/9] RapidIO: Add default handler for error_stopped state

Micha Nelissen wrote:
>
> Alexandre Bounine wrote:
> > +
> > + if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) {
> > + pr_debug("RIO_EM: servicing Output Error-Stopped
state\n");
> > + /*
> > + * Send a Link-Request/Input-Status control symbol
> > + */
> > +
> > + /* Read from link maintenance response register
> > + * to clear valid bit */
> > + rio_mport_read_config_32(mport, destid, hopcount,
> > + rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
> > + &regval);
> > + udelay(50);
>
> Perhaps this whole part of operating the MNT_RSP registers (sending
> link-request symbol is the only useful action IIRC?) can be put in a
> separate function for readability.
>
I was on the fence with this one. Now I have an extra vote in favor of a
separate function ;)
Will do.

2010-08-16 15:28:38

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 2/9] RapidIO, powerpc/85xx: modify RIO port-write interrupt handler

Micha Nelissen wrote:
>
> Alexandre Bounine wrote:
> > - Rearranged RIO port-write interrupt handling to perform message
buffering
> > as soon as possible.
>
> I don't understand this comment: you still schedule work to read the
> port-write queue; so how is this message buffering performed as soon
as
> possible?


Compared to the original code, I rearranged order of checking interrupt
status bits to check the queue status first. The 85xx PW controller is
capable to receive and keep only one PW message. Therefore, I copy it
into the driver's FIFO and re-enable HW Rx queue (it is called queue but
can accept only one entry) ASAP. I have a test setup that is capable
generate multiple PW messages and see many messages discarded by PW
controller
because of this single-entry HW queue.

>
> > - Modified to disable port-write controller when clearing
Transaction Error (TE)
> > bit.
> > /* Schedule deferred processing if PW was received */
> > - if (ipwsr & RIO_IPWSR_QFI) {
> > + if ((ipwmr & RIO_IPWMR_QFIE) && (ipwsr & RIO_IPWSR_QFI)) {
>
> Why check the QFIE bit also?

Oops! Leftover from some testing. Will clean it up.

>
> > +pw_done:
> > + if (epwisr & 0x80000000) {
>
> Magic value.


Agree. Will correct.

2010-08-16 17:11:26

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 6/9] RapidIO: Add switch-specific sysfs initialization callback

Micha Nelissen wrote:
>
> Alexandre Bounine wrote:
> > - if (!rdev->rswitch)
> > - goto out;
> > -
>
> Is it safe? All devices have a switch?

Yes. Because end-points should not have the "routes" attribute at all
(corrected by this patch).

>
> > @@ -63,10 +59,11 @@ struct device_attribute rio_dev_attrs[] = {
> > __ATTR_RO(asm_did),
> > __ATTR_RO(asm_vid),
> > __ATTR_RO(asm_rev),
> > - __ATTR_RO(routes),
> > __ATTR_NULL,
> > };
> >
> > +static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
> > +
>
> This seems a separate change from the sw_sysfs? Why make it separate?

I assume that your question was "Why do not make it separate?"
Both changes are specific to switches, both address sysfs and both are
not big enough to justify
a separate patch.
I agree that make separate patches would give more clarity, so would do
better description.
Because there are changes that should be made to other patches in this
set, I will regenerate this patch with better description.

>
> > */
> > struct rio_switch {
> > @@ -256,6 +257,7 @@ struct rio_switch {
> > u8 *sw_domain);
> > int (*em_init) (struct rio_dev *dev);
> > int (*em_handle) (struct rio_dev *dev, u8 swport);
> > + int (*sw_sysfs) (struct rio_dev *dev, int create);
> > struct rio_dev *nextdev[0];
> > };
>
> Why not make a sw_sysfs_create and sw_sysfs_remove? Is better for
> readability. Now you call 'sw_sysfs(dev, 0)' or 'sw_sysfs(dev, 1)';

I just do not want to have an extra member here. Not every switch will
require own sysfs attributes, but every switch will be presented by a
data structure. Based on its intended use I do not see any problem here.

2010-08-16 18:02:44

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 7/9] RapidIO: Add handling for PW message from a lost device

Micha Nelissen wrote:
>
> Alexandre Bounine wrote:
> > Add check if PW message source device is accessible and change PW
message
> > handler to recover if PW message source device is not available
anymore (power
> > down or link disconnect).
>
> I am not quite sure what the point is of this patch. What do you need
to
> recover from?

>From failed maintenance read. In the previous version PW handler had
troubles if maintenance
read request fails. Now I am trying to detect lost or remover devices as
soon as I see broken link.

>
> > To avoid possible loss of notification, the PW message handler scans
the route
> > back from the source device to identify end of the broken link.
>
> Do you mean if port-writes are dropped? Then they did not reach you in
> the first place. If a link in between is broken, the associated switch
> will 'complain' and send port-writes, no?

Situation that I am trying to resolve is mostly applicable to larger
systems that have multiple complex boards (or chassis/domains) connected
together. Power down sequence on the board (chassis) combined with
switch hierarchy may allow switch to send PW message to the host before
its power is off. This will create an orphaned PW message.
At the same time there is no guarantee that PW message from the
associated switch will reach the host.
That "real" PW message may be dropped by the controller (85xx is good
example). Everything depends on number of PW messages directed to the
host/controller. I am trying to use the first available notification to
service device removal. If the "real" PW message is received it should
be processed without any further action.

Alex.

2010-08-16 18:20:20

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 0/9] RapidIO: Set of patches to add Gen2 switches

Micha Nelissen wrote:
>
> Alexandre Bounine wrote:
> > This set of RapidIO patches adds support for new IDT Gen2 sRIO
switch
> > devices - CPS-1848 and CPS-1616.
> > Adding these sRIO switches required to implement standard error
recovery
> > mechanism defined by the RapidIO specification.
>
> This is not 'Gen2' specific, as these error management extensions also
> exist in v1.2/1.3 (?) of the specification? E.g. tsi56x and tsi57x
could
> support this functionality?

Correct. EM extensions exist since v1.3. But implementation before Gen2
switches relied
on proprietary device specific mechanism (tsi57x). Addition of Gen2
switches just
pushed forward the standard implementation. The RIO standard methods may
be used on 1.3 switches
(tested on tsi57x) as well as the standard routing table operations that
have been added
in our patches for 2.6.35.

>
> Micha

Alex.

2010-08-16 18:31:01

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 9/9] RapidIO: Add support for IDT CPS Gen2 switches

Micha Nelissen wrote:
>
> Alexandre Bounine wrote:
> > + rio_mport_write_config_32(mport, destid, hopcount,
> > + LOCAL_RTE_CONF_DESTID_SEL, table);
> > +
> > + for (i = 0x80000000; i <= 0x800000ff;) {
> > + rio_mport_write_config_32(mport, destid, hopcount,
> > + RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
>
> The 0x80000000 is that an autoincrement bit? If so, it only needs to
do
> this once I think? If so please call it like that, and loop the 'i'
> variable through the destination IDs.

No. This is EXTENDED_CONFIGURATION_ENABLE bit defined in Part 3 of RIO
spec (v.2.1, sect.3.5.4).
Anyway, I should add definition for this bit. Will do now.

Alex.

2010-08-17 07:08:41

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 4/9] RapidIO: Add relation links between RIO device structures

Bounine, Alexandre wrote:
>> As RapidIO is a switched network, the concept of 'previous' and 'next'
>> devices is invalid. Perhaps it's just the way they were
>> discovered/enumerated, but that does not matter any more at runtime.
>> Or at least, should not matter.
>>
>
> Yes, the "previous" and "next" have to be considered in context of
> enumeration/discovery.
> At runtime, it does not matter for data traffic, but is valuable
> information for error recovery

I agree it's desirable to have this information. Notes:
1) is rio_dev->prev used anywhere? (maybe I missed it)
2) is the nextdev[port] list complete? I mean are all connected switches
in the list? My guess is that multiply connected switches are enumerated
only once therefore only appear in the nextdev if only one switch,
instead of all
3) it would be nice to have all switch connections information.

In case ever the network is rerouted, this information will become
useful; instead of having a tree representation of the network only.

Micha

2010-08-17 07:12:43

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 2/9] RapidIO, powerpc/85xx: modify RIO port-write interrupt handler

Bounine, Alexandre wrote:
> capable to receive and keep only one PW message. Therefore, I copy it
> into the driver's FIFO and re-enable HW Rx queue (it is called queue but
> can accept only one entry) ASAP. I have a test setup that is capable
> generate multiple PW messages and see many messages discarded by PW
> controller because of this single-entry HW queue.

Primarily due to the single entry queue, the order of checking is
probably insignificant? :-) Anyway, I don't mind changing the order.

Micha

2010-08-17 07:18:15

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 6/9] RapidIO: Add switch-specific sysfs initialization callback

Bounine, Alexandre wrote:
>> Why not make a sw_sysfs_create and sw_sysfs_remove? Is better for
>> readability. Now you call 'sw_sysfs(dev, 0)' or 'sw_sysfs(dev, 1)';
>
> I just do not want to have an extra member here. Not every switch will
> require own sysfs attributes, but every switch will be presented by a
> data structure. Based on its intended use I do not see any problem here.

It's not problematic, but personally I find function calls that pass 0
or 1 as an argument hard to read. Likewise for boolean parameters. An
alternative would be to have defines SW_SYSFS_CREATE etc. It's a minor item.

Micha

2010-08-17 07:22:20

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 7/9] RapidIO: Add handling for PW message from a lost device

Bounine, Alexandre wrote:
> That "real" PW message may be dropped by the controller (85xx is good
> example). Everything depends on number of PW messages directed to the
> host/controller. I am trying to use the first available notification to
> service device removal. If the "real" PW message is received it should
> be processed without any further action.

Perhaps an idea is to use the repeated port-write sending feature so
that dropped port-writes are not a problem anymore.

Micha

2010-08-17 07:31:37

by Micha Nelissen

[permalink] [raw]
Subject: Re: [PATCH 0/9] RapidIO: Set of patches to add Gen2 switches

Bounine, Alexandre wrote:
> Micha Nelissen wrote:
>> This is not 'Gen2' specific, as these error management extensions also
>> exist in v1.2/1.3 (?) of the specification? E.g. tsi56x and tsi57x
> could
>> support this functionality?
>
> Correct. EM extensions exist since v1.3. But implementation before Gen2
> switches relied
> on proprietary device specific mechanism (tsi57x). Addition of Gen2

Do you mean the tsi56x here?

Can you explain what the difference what you mean with relied on
proprietary vs standard? E.g. setting the port-write destination ID
register is standardized? And the format of the port-write message
itself is also.

Micha

2010-08-17 12:45:11

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 7/9] RapidIO: Add handling for PW message from a lost device

Micha Nelissen wrote:
>
> Perhaps an idea is to use the repeated port-write sending feature so
> that dropped port-writes are not a problem anymore.
>
Unfortunately, this feature is not defined by RIO spec. This is
proprietary function, so we
cannot rely on it. Yes, this is nice feature of Tsi57x switches and may
be used if you have
a closed system - just enable it in em_init. The RIO spec part 8 is
quite open about port-write generation and we cannot expect the same
behavior from different devices.

2010-08-17 17:16:34

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 2/9] RapidIO, powerpc/85xx: modify RIO port-write interrupt handler

Micha Nelissen wrote:
>
> Primarily due to the single entry queue, the order of checking is
> probably insignificant? :-)

Help sometimes only but gives a feeling that I did all that is possible
;)

> Anyway, I don't mind changing the order.
>
> Micha

2010-08-17 17:21:01

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 6/9] RapidIO: Add switch-specific sysfs initialization callback

Micha Nelissen wrote:
>
> It's not problematic, but personally I find function calls that pass 0
> or 1 as an argument hard to read. Likewise for boolean parameters. An
> alternative would be to have defines SW_SYSFS_CREATE etc. It's a minor
item.
>

I will add defines.

2010-08-17 17:48:23

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 4/9] RapidIO: Add relation links between RIO device structures

Micha Nelissen wrote:
>
> I agree it's desirable to have this information. Notes:
> 1) is rio_dev->prev used anywhere? (maybe I missed it)

It is used to scan route back when servicing an orphaned PW message.
I also see its future use when invalidating route(s) in case of device
removal.

> 2) is the nextdev[port] list complete? I mean are all connected
switches
> in the list? My guess is that multiply connected switches are
enumerated
> only once therefore only appear in the nextdev if only one switch,
> instead of all
> 3) it would be nice to have all switch connections information.

Good catch. I will address this.

> In case ever the network is rerouted, this information will become
> useful; instead of having a tree representation of the network only.

I consider proposed implementation as transitional until enumeration
logic is reworked.
It already is an attempt to move towards a tree representation. Making
switch support
available was given higher priority compared to other things needed for
RIO subsystem.

Alex.

2010-08-17 18:14:22

by Bounine, Alexandre

[permalink] [raw]
Subject: RE: [PATCH 0/9] RapidIO: Set of patches to add Gen2 switches

Micha Nelissen wrote:

> Can you explain what the difference what you mean with relied on
> proprietary vs standard? E.g. setting the port-write destination ID
> register is standardized? And the format of the port-write message
> itself is also.

The original description should use "error-stopped state recovery" term
instead of simple "error recovery".
And standard based handling of error-stopped states was added. I
mentioned tsi57x in that context because it uses proprietary mechanism
to generate "magic" control symbol to clear error-stopped states. Other
switches do not have similar function and have to rely on standard
implementation.