Skip to content

Commit

Permalink
rapidio: add IDT CPS/TSI switches
Browse files Browse the repository at this point in the history
Extentions to RapidIO switch support:

1. modify switch route operation declarations to allow using single
   switch-specific file for family of switches that share the same route
   table operations.

2. add standard route table operations for switches that that support
   route table manipulation registers as defined in the Rev.1.3 of RapidIO
   specification.

3. add clear-route-table operation for switches

4. add CPSxx and TSIxxx families of RapidIO switches

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 f67231f commit 07590ff
Show file tree
Hide file tree
Showing 13 changed files with 505 additions and 11 deletions.
2 changes: 2 additions & 0 deletions drivers/rapidio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ config RAPIDIO_DISC_TIMEOUT
---help---
Amount of time a discovery node waits for a host to complete
enumeration before giving up.

source "drivers/rapidio/switches/Kconfig"
20 changes: 19 additions & 1 deletion drivers/rapidio/rio-scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static int rio_mport_phys_table[] = {
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,
};

Expand Down Expand Up @@ -246,10 +247,20 @@ static void rio_route_set_ops(struct rio_dev *rdev)
pr_debug("RIO: adding routing ops for %s\n", rio_name(rdev));
rdev->rswitch->add_entry = cur->add_hook;
rdev->rswitch->get_entry = cur->get_hook;
rdev->rswitch->clr_table = cur->clr_hook;
break;
}
cur++;
}

if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
pr_debug("RIO: adding STD routing ops for %s\n",
rio_name(rdev));
rdev->rswitch->add_entry = rio_std_route_add_entry;
rdev->rswitch->get_entry = rio_std_route_get_entry;
rdev->rswitch->clr_table = rio_std_route_clr_table;
}

if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
printk(KERN_ERR "RIO: missing routing ops for %s\n",
rio_name(rdev));
Expand Down Expand Up @@ -349,7 +360,7 @@ 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, &rdev->swpinfo);
rswitch = kmalloc(sizeof(struct rio_switch), GFP_KERNEL);
rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL);
if (!rswitch)
goto cleanup;
rswitch->switchid = next_switchid;
Expand All @@ -369,6 +380,10 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
rdev->rswitch->switchid);
rio_route_set_ops(rdev);

if (do_enum && rdev->rswitch->clr_table)
rdev->rswitch->clr_table(port, destid, hopcount,
RIO_GLOBAL_TABLE);

list_add_tail(&rswitch->node, &rio_switches);

} else
Expand Down Expand Up @@ -866,6 +881,9 @@ static void rio_update_route_tables(struct rio_mport *port)
continue;

if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {
/* Skip if destid ends in empty switch*/
if (rswitch->destid == destid)
continue;

sport = rio_get_swpinfo_inport(port,
rswitch->destid, rswitch->hopcount);
Expand Down
104 changes: 104 additions & 0 deletions drivers/rapidio/rio.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,110 @@ struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from);
}

/**
* rio_std_route_add_entry - Add switch route table entry using standard
* registers defined in RIO specification rev.1.3
* @mport: Master port to issue transaction
* @destid: Destination ID of the device
* @hopcount: Number of switch hops to the device
* @table: routing table ID (global or port-specific)
* @route_destid: destID entry in the RT
* @route_port: destination port for specified destID
*/
int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
u16 table, u16 route_destid, u8 route_port)
{
if (table == RIO_GLOBAL_TABLE) {
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);
}
udelay(10);
return 0;
}

/**
* rio_std_route_get_entry - Read switch route table entry (port number)
* assosiated with specified destID using standard registers defined in RIO
* specification rev.1.3
* @mport: Master port to issue transaction
* @destid: Destination ID of the device
* @hopcount: Number of switch hops to the device
* @table: routing table ID (global or port-specific)
* @route_destid: destID entry in the RT
* @route_port: returned destination port for specified destID
*/
int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
u16 table, u16 route_destid, u8 *route_port)
{
u32 result;

if (table == RIO_GLOBAL_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);

*route_port = (u8)result;
}

return 0;
}

/**
* rio_std_route_clr_table - Clear swotch route table using standard registers
* defined in RIO specification rev.1.3.
* @mport: Master port to issue transaction
* @local: Indicate a local master port or remote device access
* @destid: Destination ID of the device
* @hopcount: Number of switch hops to the device
* @table: routing table ID (global or port-specific)
*/
int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
u16 table)
{
u32 max_destid = 0xff;
u32 i, pef, id_inc = 1, ext_cfg = 0;
u32 port_sel = RIO_INVALID_ROUTE;

if (table == RIO_GLOBAL_TABLE) {
rio_mport_read_config_32(mport, destid, hopcount,
RIO_PEF_CAR, &pef);

if (mport->sys_size) {
rio_mport_read_config_32(mport, destid, hopcount,
RIO_SWITCH_RT_LIMIT,
&max_destid);
max_destid &= RIO_RT_MAX_DESTID;
}

if (pef & RIO_PEF_EXT_RT) {
ext_cfg = 0x80000000;
id_inc = 4;
port_sel = (RIO_INVALID_ROUTE << 24) |
(RIO_INVALID_ROUTE << 16) |
(RIO_INVALID_ROUTE << 8) |
RIO_INVALID_ROUTE;
}

for (i = 0; i <= max_destid;) {
rio_mport_write_config_32(mport, destid, hopcount,
RIO_STD_RTE_CONF_DESTID_SEL_CSR,
ext_cfg | i);
rio_mport_write_config_32(mport, destid, hopcount,
RIO_STD_RTE_CONF_PORT_SEL_CSR,
port_sel);
i += id_inc;
}
}

udelay(10);
return 0;
}

static void rio_fixup_device(struct rio_dev *dev)
{
}
Expand Down
20 changes: 14 additions & 6 deletions drivers/rapidio/rio.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid,
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);
extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid,
u8 hopcount, u16 table, u16 route_destid,
u8 route_port);
extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
u8 hopcount, u16 table, u16 route_destid,
u8 *route_port);
extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
u8 hopcount, u16 table);

/* Structures internal to the RIO core code */
extern struct device_attribute rio_dev_attrs[];
Expand All @@ -30,9 +38,9 @@ extern struct rio_route_ops __start_rio_route_ops[];
extern struct rio_route_ops __end_rio_route_ops[];

/* Helpers internal to the RIO core code */
#define DECLARE_RIO_ROUTE_SECTION(section, vid, did, add_hook, get_hook) \
static struct rio_route_ops __rio_route_ops __used \
__section(section)= { vid, did, add_hook, get_hook };
#define DECLARE_RIO_ROUTE_SECTION(section, name, vid, did, add_hook, get_hook, clr_hook) \
static const struct rio_route_ops __rio_route_##name __used \
__section(section) = { vid, did, add_hook, get_hook, clr_hook };

/**
* DECLARE_RIO_ROUTE_OPS - Registers switch routing operations
Expand All @@ -47,9 +55,9 @@ extern struct rio_route_ops __end_rio_route_ops[];
* rio_route_ops is initialized with the ops and placed into a
* RIO-specific kernel section.
*/
#define DECLARE_RIO_ROUTE_OPS(vid, did, add_hook, get_hook) \
DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, \
vid, did, add_hook, get_hook)
#define DECLARE_RIO_ROUTE_OPS(vid, did, add_hook, get_hook, clr_hook) \
DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, vid##did, \
vid, did, add_hook, get_hook, clr_hook)

#define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
#define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
28 changes: 28 additions & 0 deletions drivers/rapidio/switches/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#
# RapidIO switches configuration
#
config RAPIDIO_TSI57X
bool "IDT Tsi57x SRIO switches support"
depends on RAPIDIO
---help---
Includes support for ITD Tsi57x family of serial RapidIO switches.

config RAPIDIO_CPS_XX
bool "IDT CPS-xx SRIO switches support"
depends on RAPIDIO
---help---
Includes support for ITD CPS-16/12/10/8 serial RapidIO switches.

config RAPIDIO_TSI568
bool "Tsi568 SRIO switch support"
depends on RAPIDIO
default n
---help---
Includes support for ITD Tsi568 serial RapidIO switch.

config RAPIDIO_TSI500
bool "Tsi500 Parallel RapidIO switch support"
depends on RAPIDIO
default n
---help---
Includes support for ITD Tsi500 parallel RapidIO switch.
5 changes: 4 additions & 1 deletion drivers/rapidio/switches/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
# Makefile for RIO switches
#

obj-$(CONFIG_RAPIDIO) += tsi500.o
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
89 changes: 89 additions & 0 deletions drivers/rapidio/switches/idtcps.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* IDT CPS RapidIO switches support
*
* Copyright 2009 Integrated Device Technology, Inc.
*
* 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 "../rio.h"

#define CPS_NO_ROUTE 0xdf

static int
idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
u16 table, u16 route_destid, u8 route_port)
{
u32 result;

if (table == RIO_GLOBAL_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);

result = (0xffffff00 & result) | (u32)route_port;
rio_mport_write_config_32(mport, destid, hopcount,
RIO_STD_RTE_CONF_PORT_SEL_CSR, result);
}

return 0;
}

static int
idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
u16 table, u16 route_destid, u8 *route_port)
{
u32 result;

if (table == RIO_GLOBAL_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 (CPS_NO_ROUTE == (u8)result)
result = RIO_INVALID_ROUTE;

*route_port = (u8)result;
}

return 0;
}

static int
idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
u16 table)
{
u32 i;

if (table == RIO_GLOBAL_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,
(RIO_INVALID_ROUTE << 24) |
(RIO_INVALID_ROUTE << 16) |
(RIO_INVALID_ROUTE << 8) | RIO_INVALID_ROUTE);
i += 4;
}
}

return 0;
}

DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
DECLARE_RIO_ROUTE_OPS(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_route_add_entry, idtcps_route_get_entry, idtcps_route_clr_table);
2 changes: 1 addition & 1 deletion drivers/rapidio/switches/tsi500.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 tab
return ret;
}

DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry);
DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry, NULL);
Loading

0 comments on commit 07590ff

Please sign in to comment.