aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rapidio/switches
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rapidio/switches')
-rw-r--r--drivers/rapidio/switches/Kconfig28
-rw-r--r--drivers/rapidio/switches/Makefile9
-rw-r--r--drivers/rapidio/switches/idtcps.c137
-rw-r--r--drivers/rapidio/switches/tsi500.c20
-rw-r--r--drivers/rapidio/switches/tsi568.c146
-rw-r--r--drivers/rapidio/switches/tsi57x.c315
6 files changed, 653 insertions, 2 deletions
diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig
new file mode 100644
index 000000000000..2b4e9b2b6631
--- /dev/null
+++ b/drivers/rapidio/switches/Kconfig
@@ -0,0 +1,28 @@
1#
2# RapidIO switches configuration
3#
4config RAPIDIO_TSI57X
5 bool "IDT Tsi57x SRIO switches support"
6 depends on RAPIDIO
7 ---help---
8 Includes support for IDT Tsi57x family of serial RapidIO switches.
9
10config RAPIDIO_CPS_XX
11 bool "IDT CPS-xx SRIO switches support"
12 depends on RAPIDIO
13 ---help---
14 Includes support for IDT CPS-16/12/10/8 serial RapidIO switches.
15
16config RAPIDIO_TSI568
17 bool "Tsi568 SRIO switch support"
18 depends on RAPIDIO
19 default n
20 ---help---
21 Includes support for IDT Tsi568 serial RapidIO switch.
22
23config RAPIDIO_TSI500
24 bool "Tsi500 Parallel RapidIO switch support"
25 depends on RAPIDIO
26 default n
27 ---help---
28 Includes support for IDT Tsi500 parallel RapidIO switch.
diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile
index b924f8301761..fe4adc3e8d5f 100644
--- a/drivers/rapidio/switches/Makefile
+++ b/drivers/rapidio/switches/Makefile
@@ -2,4 +2,11 @@
2# Makefile for RIO switches 2# Makefile for RIO switches
3# 3#
4 4
5obj-$(CONFIG_RAPIDIO) += tsi500.o 5obj-$(CONFIG_RAPIDIO_TSI57X) += tsi57x.o
6obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o
7obj-$(CONFIG_RAPIDIO_TSI568) += tsi568.o
8obj-$(CONFIG_RAPIDIO_TSI500) += tsi500.o
9
10ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
11EXTRA_CFLAGS += -DDEBUG
12endif
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c
new file mode 100644
index 000000000000..2c790c144f89
--- /dev/null
+++ b/drivers/rapidio/switches/idtcps.c
@@ -0,0 +1,137 @@
1/*
2 * IDT CPS RapidIO switches support
3 *
4 * Copyright 2009-2010 Integrated Device Technology, Inc.
5 * Alexandre Bounine <alexandre.bounine@idt.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/rio.h>
14#include <linux/rio_drv.h>
15#include <linux/rio_ids.h>
16#include "../rio.h"
17
18#define CPS_DEFAULT_ROUTE 0xde
19#define CPS_NO_ROUTE 0xdf
20
21#define IDTCPS_RIO_DOMAIN 0xf20020
22
23static int
24idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
25 u16 table, u16 route_destid, u8 route_port)
26{
27 u32 result;
28
29 if (table == RIO_GLOBAL_TABLE) {
30 rio_mport_write_config_32(mport, destid, hopcount,
31 RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
32
33 rio_mport_read_config_32(mport, destid, hopcount,
34 RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
35
36 result = (0xffffff00 & result) | (u32)route_port;
37 rio_mport_write_config_32(mport, destid, hopcount,
38 RIO_STD_RTE_CONF_PORT_SEL_CSR, result);
39 }
40
41 return 0;
42}
43
44static int
45idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
46 u16 table, u16 route_destid, u8 *route_port)
47{
48 u32 result;
49
50 if (table == RIO_GLOBAL_TABLE) {
51 rio_mport_write_config_32(mport, destid, hopcount,
52 RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
53
54 rio_mport_read_config_32(mport, destid, hopcount,
55 RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
56
57 if (CPS_DEFAULT_ROUTE == (u8)result ||
58 CPS_NO_ROUTE == (u8)result)
59 *route_port = RIO_INVALID_ROUTE;
60 else
61 *route_port = (u8)result;
62 }
63
64 return 0;
65}
66
67static int
68idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
69 u16 table)
70{
71 u32 i;
72
73 if (table == RIO_GLOBAL_TABLE) {
74 for (i = 0x80000000; i <= 0x800000ff;) {
75 rio_mport_write_config_32(mport, destid, hopcount,
76 RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
77 rio_mport_write_config_32(mport, destid, hopcount,
78 RIO_STD_RTE_CONF_PORT_SEL_CSR,
79 (CPS_DEFAULT_ROUTE << 24) |
80 (CPS_DEFAULT_ROUTE << 16) |
81 (CPS_DEFAULT_ROUTE << 8) | CPS_DEFAULT_ROUTE);
82 i += 4;
83 }
84 }
85
86 return 0;
87}
88
89static int
90idtcps_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
91 u8 sw_domain)
92{
93 /*
94 * Switch domain configuration operates only at global level
95 */
96 rio_mport_write_config_32(mport, destid, hopcount,
97 IDTCPS_RIO_DOMAIN, (u32)sw_domain);
98 return 0;
99}
100
101static int
102idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
103 u8 *sw_domain)
104{
105 u32 regval;
106
107 /*
108 * Switch domain configuration operates only at global level
109 */
110 rio_mport_read_config_32(mport, destid, hopcount,
111 IDTCPS_RIO_DOMAIN, &regval);
112
113 *sw_domain = (u8)(regval & 0xff);
114
115 return 0;
116}
117
118static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
119{
120 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
121 rdev->rswitch->add_entry = idtcps_route_add_entry;
122 rdev->rswitch->get_entry = idtcps_route_get_entry;
123 rdev->rswitch->clr_table = idtcps_route_clr_table;
124 rdev->rswitch->set_domain = idtcps_set_domain;
125 rdev->rswitch->get_domain = idtcps_get_domain;
126 rdev->rswitch->em_init = NULL;
127 rdev->rswitch->em_handle = NULL;
128
129 return 0;
130}
131
132DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_switch_init);
133DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_switch_init);
134DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_switch_init);
135DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_switch_init);
136DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_switch_init);
137DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_switch_init);
diff --git a/drivers/rapidio/switches/tsi500.c b/drivers/rapidio/switches/tsi500.c
index c77c23bd9840..914eddd5aa42 100644
--- a/drivers/rapidio/switches/tsi500.c
+++ b/drivers/rapidio/switches/tsi500.c
@@ -1,6 +1,10 @@
1/* 1/*
2 * RapidIO Tsi500 switch support 2 * RapidIO Tsi500 switch support
3 * 3 *
4 * Copyright 2009-2010 Integrated Device Technology, Inc.
5 * Alexandre Bounine <alexandre.bounine@idt.com>
6 * - Modified switch operations initialization.
7 *
4 * Copyright 2005 MontaVista Software, Inc. 8 * Copyright 2005 MontaVista Software, Inc.
5 * Matt Porter <mporter@kernel.crashing.org> 9 * Matt Porter <mporter@kernel.crashing.org>
6 * 10 *
@@ -57,4 +61,18 @@ tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 tab
57 return ret; 61 return ret;
58} 62}
59 63
60DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry); 64static int tsi500_switch_init(struct rio_dev *rdev, int do_enum)
65{
66 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
67 rdev->rswitch->add_entry = tsi500_route_add_entry;
68 rdev->rswitch->get_entry = tsi500_route_get_entry;
69 rdev->rswitch->clr_table = NULL;
70 rdev->rswitch->set_domain = NULL;
71 rdev->rswitch->get_domain = NULL;
72 rdev->rswitch->em_init = NULL;
73 rdev->rswitch->em_handle = NULL;
74
75 return 0;
76}
77
78DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_switch_init);
diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c
new file mode 100644
index 000000000000..f7fd7898606e
--- /dev/null
+++ b/drivers/rapidio/switches/tsi568.c
@@ -0,0 +1,146 @@
1/*
2 * RapidIO Tsi568 switch support
3 *
4 * Copyright 2009-2010 Integrated Device Technology, Inc.
5 * Alexandre Bounine <alexandre.bounine@idt.com>
6 * - Added EM support
7 * - Modified switch operations initialization.
8 *
9 * Copyright 2005 MontaVista Software, Inc.
10 * Matt Porter <mporter@kernel.crashing.org>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17
18#include <linux/rio.h>
19#include <linux/rio_drv.h>
20#include <linux/rio_ids.h>
21#include <linux/delay.h>
22#include "../rio.h"
23
24/* Global (broadcast) route registers */
25#define SPBC_ROUTE_CFG_DESTID 0x10070
26#define SPBC_ROUTE_CFG_PORT 0x10074
27
28/* Per port route registers */
29#define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n)
30#define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n)
31
32#define TSI568_SP_MODE_BC 0x10004
33#define TSI568_SP_MODE_PW_DIS 0x08000000
34
35static int
36tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
37 u16 table, u16 route_destid, u8 route_port)
38{
39 if (table == RIO_GLOBAL_TABLE) {
40 rio_mport_write_config_32(mport, destid, hopcount,
41 SPBC_ROUTE_CFG_DESTID, route_destid);
42 rio_mport_write_config_32(mport, destid, hopcount,
43 SPBC_ROUTE_CFG_PORT, route_port);
44 } else {
45 rio_mport_write_config_32(mport, destid, hopcount,
46 SPP_ROUTE_CFG_DESTID(table),
47 route_destid);
48 rio_mport_write_config_32(mport, destid, hopcount,
49 SPP_ROUTE_CFG_PORT(table), route_port);
50 }
51
52 udelay(10);
53
54 return 0;
55}
56
57static int
58tsi568_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
59 u16 table, u16 route_destid, u8 *route_port)
60{
61 int ret = 0;
62 u32 result;
63
64 if (table == RIO_GLOBAL_TABLE) {
65 rio_mport_write_config_32(mport, destid, hopcount,
66 SPBC_ROUTE_CFG_DESTID, route_destid);
67 rio_mport_read_config_32(mport, destid, hopcount,
68 SPBC_ROUTE_CFG_PORT, &result);
69 } else {
70 rio_mport_write_config_32(mport, destid, hopcount,
71 SPP_ROUTE_CFG_DESTID(table),
72 route_destid);
73 rio_mport_read_config_32(mport, destid, hopcount,
74 SPP_ROUTE_CFG_PORT(table), &result);
75 }
76
77 *route_port = result;
78 if (*route_port > 15)
79 ret = -1;
80
81 return ret;
82}
83
84static int
85tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
86 u16 table)
87{
88 u32 route_idx;
89 u32 lut_size;
90
91 lut_size = (mport->sys_size) ? 0x1ff : 0xff;
92
93 if (table == RIO_GLOBAL_TABLE) {
94 rio_mport_write_config_32(mport, destid, hopcount,
95 SPBC_ROUTE_CFG_DESTID, 0x80000000);
96 for (route_idx = 0; route_idx <= lut_size; route_idx++)
97 rio_mport_write_config_32(mport, destid, hopcount,
98 SPBC_ROUTE_CFG_PORT,
99 RIO_INVALID_ROUTE);
100 } else {
101 rio_mport_write_config_32(mport, destid, hopcount,
102 SPP_ROUTE_CFG_DESTID(table),
103 0x80000000);
104 for (route_idx = 0; route_idx <= lut_size; route_idx++)
105 rio_mport_write_config_32(mport, destid, hopcount,
106 SPP_ROUTE_CFG_PORT(table),
107 RIO_INVALID_ROUTE);
108 }
109
110 return 0;
111}
112
113static int
114tsi568_em_init(struct rio_dev *rdev)
115{
116 struct rio_mport *mport = rdev->net->hport;
117 u16 destid = rdev->rswitch->destid;
118 u8 hopcount = rdev->rswitch->hopcount;
119 u32 regval;
120
121 pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount);
122
123 /* Make sure that Port-Writes are disabled (for all ports) */
124 rio_mport_read_config_32(mport, destid, hopcount,
125 TSI568_SP_MODE_BC, &regval);
126 rio_mport_write_config_32(mport, destid, hopcount,
127 TSI568_SP_MODE_BC, regval | TSI568_SP_MODE_PW_DIS);
128
129 return 0;
130}
131
132static int tsi568_switch_init(struct rio_dev *rdev, int do_enum)
133{
134 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
135 rdev->rswitch->add_entry = tsi568_route_add_entry;
136 rdev->rswitch->get_entry = tsi568_route_get_entry;
137 rdev->rswitch->clr_table = tsi568_route_clr_table;
138 rdev->rswitch->set_domain = NULL;
139 rdev->rswitch->get_domain = NULL;
140 rdev->rswitch->em_init = tsi568_em_init;
141 rdev->rswitch->em_handle = NULL;
142
143 return 0;
144}
145
146DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init);
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c
new file mode 100644
index 000000000000..d34df722d95f
--- /dev/null
+++ b/drivers/rapidio/switches/tsi57x.c
@@ -0,0 +1,315 @@
1/*
2 * RapidIO Tsi57x switch family support
3 *
4 * Copyright 2009-2010 Integrated Device Technology, Inc.
5 * Alexandre Bounine <alexandre.bounine@idt.com>
6 * - Added EM support
7 * - Modified switch operations initialization.
8 *
9 * Copyright 2005 MontaVista Software, Inc.
10 * Matt Porter <mporter@kernel.crashing.org>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17
18#include <linux/rio.h>
19#include <linux/rio_drv.h>
20#include <linux/rio_ids.h>
21#include <linux/delay.h>
22#include "../rio.h"
23
24/* Global (broadcast) route registers */
25#define SPBC_ROUTE_CFG_DESTID 0x10070
26#define SPBC_ROUTE_CFG_PORT 0x10074
27
28/* Per port route registers */
29#define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n)
30#define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n)
31
32#define TSI578_SP_MODE(n) (0x11004 + n*0x100)
33#define TSI578_SP_MODE_GLBL 0x10004
34#define TSI578_SP_MODE_PW_DIS 0x08000000
35#define TSI578_SP_MODE_LUT_512 0x01000000
36
37#define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100)
38#define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100)
39#define TSI578_SP_CS_TX(n) (0x13014 + n*0x100)
40#define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100)
41
42#define TSI578_GLBL_ROUTE_BASE 0x10078
43
44static int
45tsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
46 u16 table, u16 route_destid, u8 route_port)
47{
48 if (table == RIO_GLOBAL_TABLE) {
49 rio_mport_write_config_32(mport, destid, hopcount,
50 SPBC_ROUTE_CFG_DESTID, route_destid);
51 rio_mport_write_config_32(mport, destid, hopcount,
52 SPBC_ROUTE_CFG_PORT, route_port);
53 } else {
54 rio_mport_write_config_32(mport, destid, hopcount,
55 SPP_ROUTE_CFG_DESTID(table), route_destid);
56 rio_mport_write_config_32(mport, destid, hopcount,
57 SPP_ROUTE_CFG_PORT(table), route_port);
58 }
59
60 udelay(10);
61
62 return 0;
63}
64
65static int
66tsi57x_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
67 u16 table, u16 route_destid, u8 *route_port)
68{
69 int ret = 0;
70 u32 result;
71
72 if (table == RIO_GLOBAL_TABLE) {
73 /* Use local RT of the ingress port to avoid possible
74 race condition */
75 rio_mport_read_config_32(mport, destid, hopcount,
76 RIO_SWP_INFO_CAR, &result);
77 table = (result & RIO_SWP_INFO_PORT_NUM_MASK);
78 }
79
80 rio_mport_write_config_32(mport, destid, hopcount,
81 SPP_ROUTE_CFG_DESTID(table), route_destid);
82 rio_mport_read_config_32(mport, destid, hopcount,
83 SPP_ROUTE_CFG_PORT(table), &result);
84
85 *route_port = (u8)result;
86 if (*route_port > 15)
87 ret = -1;
88
89 return ret;
90}
91
92static int
93tsi57x_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
94 u16 table)
95{
96 u32 route_idx;
97 u32 lut_size;
98
99 lut_size = (mport->sys_size) ? 0x1ff : 0xff;
100
101 if (table == RIO_GLOBAL_TABLE) {
102 rio_mport_write_config_32(mport, destid, hopcount,
103 SPBC_ROUTE_CFG_DESTID, 0x80000000);
104 for (route_idx = 0; route_idx <= lut_size; route_idx++)
105 rio_mport_write_config_32(mport, destid, hopcount,
106 SPBC_ROUTE_CFG_PORT,
107 RIO_INVALID_ROUTE);
108 } else {
109 rio_mport_write_config_32(mport, destid, hopcount,
110 SPP_ROUTE_CFG_DESTID(table), 0x80000000);
111 for (route_idx = 0; route_idx <= lut_size; route_idx++)
112 rio_mport_write_config_32(mport, destid, hopcount,
113 SPP_ROUTE_CFG_PORT(table) , RIO_INVALID_ROUTE);
114 }
115
116 return 0;
117}
118
119static int
120tsi57x_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
121 u8 sw_domain)
122{
123 u32 regval;
124
125 /*
126 * Switch domain configuration operates only at global level
127 */
128
129 /* Turn off flat (LUT_512) mode */
130 rio_mport_read_config_32(mport, destid, hopcount,
131 TSI578_SP_MODE_GLBL, &regval);
132 rio_mport_write_config_32(mport, destid, hopcount, TSI578_SP_MODE_GLBL,
133 regval & ~TSI578_SP_MODE_LUT_512);
134 /* Set switch domain base */
135 rio_mport_write_config_32(mport, destid, hopcount,
136 TSI578_GLBL_ROUTE_BASE,
137 (u32)(sw_domain << 24));
138 return 0;
139}
140
141static int
142tsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
143 u8 *sw_domain)
144{
145 u32 regval;
146
147 /*
148 * Switch domain configuration operates only at global level
149 */
150 rio_mport_read_config_32(mport, destid, hopcount,
151 TSI578_GLBL_ROUTE_BASE, &regval);
152
153 *sw_domain = (u8)(regval >> 24);
154
155 return 0;
156}
157
158static int
159tsi57x_em_init(struct rio_dev *rdev)
160{
161 struct rio_mport *mport = rdev->net->hport;
162 u16 destid = rdev->rswitch->destid;
163 u8 hopcount = rdev->rswitch->hopcount;
164 u32 regval;
165 int portnum;
166
167 pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount);
168
169 for (portnum = 0; portnum < 16; portnum++) {
170 /* Make sure that Port-Writes are enabled (for all ports) */
171 rio_mport_read_config_32(mport, destid, hopcount,
172 TSI578_SP_MODE(portnum), &regval);
173 rio_mport_write_config_32(mport, destid, hopcount,
174 TSI578_SP_MODE(portnum),
175 regval & ~TSI578_SP_MODE_PW_DIS);
176
177 /* Clear all pending interrupts */
178 rio_mport_read_config_32(mport, destid, hopcount,
179 rdev->phys_efptr +
180 RIO_PORT_N_ERR_STS_CSR(portnum),
181 &regval);
182 rio_mport_write_config_32(mport, destid, hopcount,
183 rdev->phys_efptr +
184 RIO_PORT_N_ERR_STS_CSR(portnum),
185 regval & 0x07120214);
186
187 rio_mport_read_config_32(mport, destid, hopcount,
188 TSI578_SP_INT_STATUS(portnum), &regval);
189 rio_mport_write_config_32(mport, destid, hopcount,
190 TSI578_SP_INT_STATUS(portnum),
191 regval & 0x000700bd);
192
193 /* Enable all interrupts to allow ports to send a port-write */
194 rio_mport_read_config_32(mport, destid, hopcount,
195 TSI578_SP_CTL_INDEP(portnum), &regval);
196 rio_mport_write_config_32(mport, destid, hopcount,
197 TSI578_SP_CTL_INDEP(portnum),
198 regval | 0x000b0000);
199
200 /* Skip next (odd) port if the current port is in x4 mode */
201 rio_mport_read_config_32(mport, destid, hopcount,
202 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
203 &regval);
204 if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4)
205 portnum++;
206 }
207
208 return 0;
209}
210
211static int
212tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
213{
214 struct rio_mport *mport = rdev->net->hport;
215 u16 destid = rdev->rswitch->destid;
216 u8 hopcount = rdev->rswitch->hopcount;
217 u32 intstat, err_status;
218 int sendcount, checkcount;
219 u8 route_port;
220 u32 regval;
221
222 rio_mport_read_config_32(mport, destid, hopcount,
223 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
224 &err_status);
225
226 if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) &&
227 (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
228 RIO_PORT_N_ERR_STS_PW_INP_ES))) {
229 /* Remove any queued packets by locking/unlocking port */
230 rio_mport_read_config_32(mport, destid, hopcount,
231 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
232 &regval);
233 if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) {
234 rio_mport_write_config_32(mport, destid, hopcount,
235 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
236 regval | RIO_PORT_N_CTL_LOCKOUT);
237 udelay(50);
238 rio_mport_write_config_32(mport, destid, hopcount,
239 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
240 regval);
241 }
242
243 /* Read from link maintenance response register to clear
244 * valid bit
245 */
246 rio_mport_read_config_32(mport, destid, hopcount,
247 rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum),
248 &regval);
249
250 /* Send a Packet-Not-Accepted/Link-Request-Input-Status control
251 * symbol to recover from IES/OES
252 */
253 sendcount = 3;
254 while (sendcount) {
255 rio_mport_write_config_32(mport, destid, hopcount,
256 TSI578_SP_CS_TX(portnum), 0x40fc8000);
257 checkcount = 3;
258 while (checkcount--) {
259 udelay(50);
260 rio_mport_read_config_32(
261 mport, destid, hopcount,
262 rdev->phys_efptr +
263 RIO_PORT_N_MNT_RSP_CSR(portnum),
264 &regval);
265 if (regval & RIO_PORT_N_MNT_RSP_RVAL)
266 goto exit_es;
267 }
268
269 sendcount--;
270 }
271 }
272
273exit_es:
274 /* Clear implementation specific error status bits */
275 rio_mport_read_config_32(mport, destid, hopcount,
276 TSI578_SP_INT_STATUS(portnum), &intstat);
277 pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n",
278 destid, hopcount, portnum, intstat);
279
280 if (intstat & 0x10000) {
281 rio_mport_read_config_32(mport, destid, hopcount,
282 TSI578_SP_LUT_PEINF(portnum), &regval);
283 regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24);
284 route_port = rdev->rswitch->route_table[regval];
285 pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n",
286 rio_name(rdev), portnum, regval);
287 tsi57x_route_add_entry(mport, destid, hopcount,
288 RIO_GLOBAL_TABLE, regval, route_port);
289 }
290
291 rio_mport_write_config_32(mport, destid, hopcount,
292 TSI578_SP_INT_STATUS(portnum),
293 intstat & 0x000700bd);
294
295 return 0;
296}
297
298static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum)
299{
300 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
301 rdev->rswitch->add_entry = tsi57x_route_add_entry;
302 rdev->rswitch->get_entry = tsi57x_route_get_entry;
303 rdev->rswitch->clr_table = tsi57x_route_clr_table;
304 rdev->rswitch->set_domain = tsi57x_set_domain;
305 rdev->rswitch->get_domain = tsi57x_get_domain;
306 rdev->rswitch->em_init = tsi57x_em_init;
307 rdev->rswitch->em_handle = tsi57x_em_handler;
308
309 return 0;
310}
311
312DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_switch_init);
313DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_switch_init);
314DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_switch_init);
315DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_switch_init);