Skip to content

Commit

Permalink
rapidio: add Port-Write handling for EM
Browse files Browse the repository at this point in the history
Add RapidIO Port-Write message handling in the context of Error
   Management Extensions Specification Rev.1.3.

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>
  • Loading branch information
Alexandre Bounine authored and Linus Torvalds committed May 27, 2010
1 parent 818a04a commit e5cabeb
Show file tree
Hide file tree
Showing 10 changed files with 776 additions and 41 deletions.
2 changes: 1 addition & 1 deletion arch/powerpc/sysdev/fsl_rio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ int fsl_rio_setup(struct of_device *dev)
dev_info(&dev->dev, "LAW start 0x%016llx, size 0x%016llx.\n",
law_start, law_size);

ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL);
if (!ops) {
rc = -ENOMEM;
goto err_ops;
Expand Down
166 changes: 130 additions & 36 deletions drivers/rapidio/rio-scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
* Copyright 2009 Integrated Device Technology, Inc.
* Alex Bounine <alexandre.bounine@idt.com>
* - Added Port-Write/Error Management initialization and handling
*
* 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
Expand Down Expand Up @@ -31,15 +35,16 @@
LIST_HEAD(rio_devices);
static LIST_HEAD(rio_switches);

#define RIO_ENUM_CMPL_MAGIC 0xdeadbeef

static void rio_enum_timeout(unsigned long);

static void rio_init_em(struct rio_dev *rdev);

DEFINE_SPINLOCK(rio_global_list_lock);

static int next_destid = 0;
static int next_switchid = 0;
static int next_net = 0;
static int next_comptag;

static struct timer_list rio_enum_timer =
TIMER_INITIALIZER(rio_enum_timeout, 0, 0);
Expand All @@ -52,13 +57,6 @@ static int rio_mport_phys_table[] = {
-1,
};

static int rio_sport_phys_table[] = {
RIO_EFB_PAR_EP_FREE_ID,
RIO_EFB_SER_EP_FREE_ID,
RIO_EFB_SER_EP_FREC_ID,
-1,
};

/**
* rio_get_device_id - Get the base/extended device id for a device
* @port: RIO master port
Expand Down Expand Up @@ -119,12 +117,26 @@ static int rio_clear_locks(struct rio_mport *port)
u32 result;
int ret = 0;

/* Write component tag CSR magic complete value */
rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR,
RIO_ENUM_CMPL_MAGIC);
list_for_each_entry(rdev, &rio_devices, global_list)
rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR,
RIO_ENUM_CMPL_MAGIC);
/* Assign component tag to all devices */
next_comptag = 1;
rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++);

list_for_each_entry(rdev, &rio_devices, global_list) {
/* Mark device as discovered */
rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
&result);
rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
result | RIO_PORT_GEN_DISCOVERED);

rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag);
rdev->comp_tag = next_comptag++;
if (next_comptag >= 0x10000) {
pr_err("RIO: Component Tag Counter Overflow\n");
break;
}
}

/* Release host device id locks */
rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
Expand Down Expand Up @@ -266,6 +278,30 @@ static void rio_route_set_ops(struct rio_dev *rdev)
rio_name(rdev));
}

/**
* rio_em_set_ops- Sets Error Managment operations for a particular vendor switch
* @rdev: RIO device
*
* Searches the RIO EM ops table for known switch types. If the vid
* and did match a switch table entry, then set the em_init() and
* em_handle() ops to the table entry values.
*/
static void rio_em_set_ops(struct rio_dev *rdev)
{
struct rio_em_ops *cur = __start_rio_em_ops;
struct rio_em_ops *end = __end_rio_em_ops;

while (cur < end) {
if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
pr_debug("RIO: adding EM ops for %s\n", rio_name(rdev));
rdev->rswitch->em_init = cur->init_hook;
rdev->rswitch->em_handle = cur->handler_hook;
break;
}
cur++;
}
}

/**
* rio_add_device- Adds a RIO device to the device model
* @rdev: RIO device
Expand Down Expand Up @@ -336,8 +372,14 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rdev->asm_rev = result >> 16;
rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR,
&rdev->pef);
if (rdev->pef & RIO_PEF_EXT_FEATURES)
if (rdev->pef & RIO_PEF_EXT_FEATURES) {
rdev->efptr = result & 0xffff;
rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid,
hopcount);

rdev->em_efptr = rio_mport_get_feature(port, 0, destid,
hopcount, RIO_EFB_ERR_MGMNT);
}

rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
&rdev->src_ops);
Expand Down Expand Up @@ -366,6 +408,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rswitch->switchid = next_switchid;
rswitch->hopcount = hopcount;
rswitch->destid = destid;
rswitch->port_ok = 0;
rswitch->route_table = kzalloc(sizeof(u8)*
RIO_MAX_ROUTE_ENTRIES(port->sys_size),
GFP_KERNEL);
Expand All @@ -379,6 +422,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
rdev->rswitch->switchid);
rio_route_set_ops(rdev);
rio_em_set_ops(rdev);

if (do_enum && rdev->rswitch->clr_table)
rdev->rswitch->clr_table(port, destid, hopcount,
Expand Down Expand Up @@ -429,31 +473,37 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
*
* Reads the port error status CSR for a particular switch port to
* determine if the port has an active link. Returns
* %PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
* %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
* inactive.
*/
static int
rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
{
u32 result;
u32 result = 0;
u32 ext_ftr_ptr;

int *entry = rio_sport_phys_table;

do {
if ((ext_ftr_ptr =
rio_mport_get_feature(port, 0, destid, hopcount, *entry)))
ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0);

while (ext_ftr_ptr) {
rio_mport_read_config_32(port, destid, hopcount,
ext_ftr_ptr, &result);
result = RIO_GET_BLOCK_ID(result);
if ((result == RIO_EFB_SER_EP_FREE_ID) ||
(result == RIO_EFB_SER_EP_FREE_ID_V13P) ||
(result == RIO_EFB_SER_EP_FREC_ID))
break;
} while (*++entry >= 0);

ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount,
ext_ftr_ptr);
}

if (ext_ftr_ptr)
rio_mport_read_config_32(port, destid, hopcount,
ext_ftr_ptr +
RIO_PORT_N_ERR_STS_CSR(sport),
&result);

return (result & PORT_N_ERR_STS_PORT_OK);
return result & RIO_PORT_N_ERR_STS_PORT_OK;
}

/**
Expand Down Expand Up @@ -762,8 +812,10 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
rio_name(rdev), rdev->vid, rdev->did, num_ports);
sw_destid = next_destid;
for (port_num = 0; port_num < num_ports; port_num++) {
if (sw_inport == port_num)
if (sw_inport == port_num) {
rdev->rswitch->port_ok |= (1 << port_num);
continue;
}

cur_destid = next_destid;

Expand All @@ -773,6 +825,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
pr_debug(
"RIO: scanning device on port %d\n",
port_num);
rdev->rswitch->port_ok |= (1 << port_num);
rio_route_add_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE,
RIO_ANY_DESTID(port->sys_size),
Expand All @@ -797,9 +850,28 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
port_num;
}
}
} else {
/* If switch supports Error Management,
* set PORT_LOCKOUT bit for unused port
*/
if (rdev->em_efptr)
rio_set_port_lockout(rdev, port_num, 1);

rdev->rswitch->port_ok &= ~(1 << port_num);
}
}

/* Direct Port-write messages to the enumeratiing host */
if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) &&
(rdev->em_efptr)) {
rio_write_config_32(rdev,
rdev->em_efptr + RIO_EM_PW_TGT_DEVID,
(port->host_deviceid << 16) |
(port->sys_size << 15));
}

rio_init_em(rdev);

/* Check for empty switch */
if (next_destid == sw_destid) {
next_destid++;
Expand All @@ -819,21 +891,16 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
* rio_enum_complete- Tests if enumeration of a network is complete
* @port: Master port to send transaction
*
* Tests the Component Tag CSR for presence of the magic enumeration
* complete flag. Return %1 if enumeration is complete or %0 if
* Tests the Component Tag CSR for non-zero value (enumeration
* complete flag). Return %1 if enumeration is complete or %0 if
* enumeration is incomplete.
*/
static int rio_enum_complete(struct rio_mport *port)
{
u32 tag_csr;
int ret = 0;

rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr);

if (tag_csr == RIO_ENUM_CMPL_MAGIC)
ret = 1;

return ret;
return (tag_csr & 0xffff) ? 1 : 0;
}

/**
Expand Down Expand Up @@ -915,7 +982,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
*
* Reads the port error status CSR for the master port to
* determine if the port has an active link. Returns
* %PORT_N_ERR_STS_PORT_OK if the master port is active
* %RIO_PORT_N_ERR_STS_PORT_OK if the master port is active
* or %0 if it is inactive.
*/
static int rio_mport_is_active(struct rio_mport *port)
Expand All @@ -936,7 +1003,7 @@ static int rio_mport_is_active(struct rio_mport *port)
RIO_PORT_N_ERR_STS_CSR(port->index),
&result);

return (result & PORT_N_ERR_STS_PORT_OK);
return result & RIO_PORT_N_ERR_STS_PORT_OK;
}

/**
Expand Down Expand Up @@ -1007,6 +1074,32 @@ static void rio_update_route_tables(struct rio_mport *port)
}
}

/**
* rio_init_em - Initializes RIO Error Management (for switches)
* @port: Master port associated with the RIO network
*
* For each enumerated switch, call device-specific error management
* initialization routine (if supplied by the switch driver).
*/
static void rio_init_em(struct rio_dev *rdev)
{
if (rio_is_switch(rdev) && (rdev->em_efptr) &&
(rdev->rswitch->em_init)) {
rdev->rswitch->em_init(rdev);
}
}

/**
* rio_pw_enable - Enables/disables port-write handling by a master port
* @port: Master port associated with port-write handling
* @enable: 1=enable, 0=disable
*/
static void rio_pw_enable(struct rio_mport *port, int enable)
{
if (port->ops->pwenable)
port->ops->pwenable(port, enable);
}

/**
* rio_enum_mport- Start enumeration through a master port
* @mport: Master port to send transactions
Expand Down Expand Up @@ -1050,6 +1143,7 @@ int __devinit rio_enum_mport(struct rio_mport *mport)
}
rio_update_route_tables(mport);
rio_clear_locks(mport);
rio_pw_enable(mport, 1);
} else {
printk(KERN_INFO "RIO: master port %d link inactive\n",
mport->id);
Expand Down
Loading

0 comments on commit e5cabeb

Please sign in to comment.