]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/rapidio/switches/tsi57x.c
rapidio: modify initialization of switch operations
[net-next-2.6.git] / drivers / rapidio / switches / tsi57x.c
CommitLineData
07590ff0
AB
1/*
2 * RapidIO Tsi57x switch family support
3 *
058f88d6
AB
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 *
07590ff0
AB
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
e5cabeb3
AB
32#define TSI578_SP_MODE(n) (0x11004 + n*0x100)
33#define TSI578_SP_MODE_PW_DIS 0x08000000
34
35#define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100)
36#define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100)
37#define TSI578_SP_CS_TX(n) (0x13014 + n*0x100)
38#define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100)
39
07590ff0
AB
40static int
41tsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
42 u16 table, u16 route_destid, u8 route_port)
43{
44 if (table == RIO_GLOBAL_TABLE) {
45 rio_mport_write_config_32(mport, destid, hopcount,
46 SPBC_ROUTE_CFG_DESTID, route_destid);
47 rio_mport_write_config_32(mport, destid, hopcount,
48 SPBC_ROUTE_CFG_PORT, route_port);
49 } else {
50 rio_mport_write_config_32(mport, destid, hopcount,
51 SPP_ROUTE_CFG_DESTID(table), route_destid);
52 rio_mport_write_config_32(mport, destid, hopcount,
53 SPP_ROUTE_CFG_PORT(table), route_port);
54 }
55
56 udelay(10);
57
58 return 0;
59}
60
61static int
62tsi57x_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
63 u16 table, u16 route_destid, u8 *route_port)
64{
65 int ret = 0;
66 u32 result;
67
68 if (table == RIO_GLOBAL_TABLE) {
69 /* Use local RT of the ingress port to avoid possible
70 race condition */
71 rio_mport_read_config_32(mport, destid, hopcount,
72 RIO_SWP_INFO_CAR, &result);
73 table = (result & RIO_SWP_INFO_PORT_NUM_MASK);
74 }
75
76 rio_mport_write_config_32(mport, destid, hopcount,
77 SPP_ROUTE_CFG_DESTID(table), route_destid);
78 rio_mport_read_config_32(mport, destid, hopcount,
79 SPP_ROUTE_CFG_PORT(table), &result);
80
81 *route_port = (u8)result;
82 if (*route_port > 15)
83 ret = -1;
84
85 return ret;
86}
87
88static int
89tsi57x_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
90 u16 table)
91{
92 u32 route_idx;
93 u32 lut_size;
94
95 lut_size = (mport->sys_size) ? 0x1ff : 0xff;
96
97 if (table == RIO_GLOBAL_TABLE) {
98 rio_mport_write_config_32(mport, destid, hopcount,
99 SPBC_ROUTE_CFG_DESTID, 0x80000000);
100 for (route_idx = 0; route_idx <= lut_size; route_idx++)
101 rio_mport_write_config_32(mport, destid, hopcount,
102 SPBC_ROUTE_CFG_PORT,
103 RIO_INVALID_ROUTE);
104 } else {
105 rio_mport_write_config_32(mport, destid, hopcount,
106 SPP_ROUTE_CFG_DESTID(table), 0x80000000);
107 for (route_idx = 0; route_idx <= lut_size; route_idx++)
108 rio_mport_write_config_32(mport, destid, hopcount,
109 SPP_ROUTE_CFG_PORT(table) , RIO_INVALID_ROUTE);
110 }
111
112 return 0;
113}
114
e5cabeb3
AB
115static int
116tsi57x_em_init(struct rio_dev *rdev)
117{
118 struct rio_mport *mport = rdev->net->hport;
119 u16 destid = rdev->rswitch->destid;
120 u8 hopcount = rdev->rswitch->hopcount;
121 u32 regval;
122 int portnum;
123
124 pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount);
125
126 for (portnum = 0; portnum < 16; portnum++) {
127 /* Make sure that Port-Writes are enabled (for all ports) */
128 rio_mport_read_config_32(mport, destid, hopcount,
129 TSI578_SP_MODE(portnum), &regval);
130 rio_mport_write_config_32(mport, destid, hopcount,
131 TSI578_SP_MODE(portnum),
132 regval & ~TSI578_SP_MODE_PW_DIS);
133
134 /* Clear all pending interrupts */
135 rio_mport_read_config_32(mport, destid, hopcount,
136 rdev->phys_efptr +
137 RIO_PORT_N_ERR_STS_CSR(portnum),
138 &regval);
139 rio_mport_write_config_32(mport, destid, hopcount,
140 rdev->phys_efptr +
141 RIO_PORT_N_ERR_STS_CSR(portnum),
142 regval & 0x07120214);
143
144 rio_mport_read_config_32(mport, destid, hopcount,
145 TSI578_SP_INT_STATUS(portnum), &regval);
146 rio_mport_write_config_32(mport, destid, hopcount,
147 TSI578_SP_INT_STATUS(portnum),
148 regval & 0x000700bd);
149
150 /* Enable all interrupts to allow ports to send a port-write */
151 rio_mport_read_config_32(mport, destid, hopcount,
152 TSI578_SP_CTL_INDEP(portnum), &regval);
153 rio_mport_write_config_32(mport, destid, hopcount,
154 TSI578_SP_CTL_INDEP(portnum),
155 regval | 0x000b0000);
156
157 /* Skip next (odd) port if the current port is in x4 mode */
158 rio_mport_read_config_32(mport, destid, hopcount,
159 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
160 &regval);
161 if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4)
162 portnum++;
163 }
164
165 return 0;
166}
167
168static int
169tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
170{
171 struct rio_mport *mport = rdev->net->hport;
172 u16 destid = rdev->rswitch->destid;
173 u8 hopcount = rdev->rswitch->hopcount;
174 u32 intstat, err_status;
175 int sendcount, checkcount;
176 u8 route_port;
177 u32 regval;
178
179 rio_mport_read_config_32(mport, destid, hopcount,
180 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
181 &err_status);
182
183 if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) &&
184 (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
185 RIO_PORT_N_ERR_STS_PW_INP_ES))) {
186 /* Remove any queued packets by locking/unlocking port */
187 rio_mport_read_config_32(mport, destid, hopcount,
188 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
189 &regval);
190 if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) {
191 rio_mport_write_config_32(mport, destid, hopcount,
192 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
193 regval | RIO_PORT_N_CTL_LOCKOUT);
194 udelay(50);
195 rio_mport_write_config_32(mport, destid, hopcount,
196 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
197 regval);
198 }
199
200 /* Read from link maintenance response register to clear
201 * valid bit
202 */
203 rio_mport_read_config_32(mport, destid, hopcount,
204 rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum),
205 &regval);
206
207 /* Send a Packet-Not-Accepted/Link-Request-Input-Status control
208 * symbol to recover from IES/OES
209 */
210 sendcount = 3;
211 while (sendcount) {
212 rio_mport_write_config_32(mport, destid, hopcount,
213 TSI578_SP_CS_TX(portnum), 0x40fc8000);
214 checkcount = 3;
215 while (checkcount--) {
216 udelay(50);
217 rio_mport_read_config_32(
218 mport, destid, hopcount,
219 rdev->phys_efptr +
220 RIO_PORT_N_MNT_RSP_CSR(portnum),
221 &regval);
222 if (regval & RIO_PORT_N_MNT_RSP_RVAL)
223 goto exit_es;
224 }
225
226 sendcount--;
227 }
228 }
229
230exit_es:
231 /* Clear implementation specific error status bits */
232 rio_mport_read_config_32(mport, destid, hopcount,
233 TSI578_SP_INT_STATUS(portnum), &intstat);
234 pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n",
235 destid, hopcount, portnum, intstat);
236
237 if (intstat & 0x10000) {
238 rio_mport_read_config_32(mport, destid, hopcount,
239 TSI578_SP_LUT_PEINF(portnum), &regval);
240 regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24);
241 route_port = rdev->rswitch->route_table[regval];
242 pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n",
243 rio_name(rdev), portnum, regval);
244 tsi57x_route_add_entry(mport, destid, hopcount,
245 RIO_GLOBAL_TABLE, regval, route_port);
246 }
247
248 rio_mport_write_config_32(mport, destid, hopcount,
249 TSI578_SP_INT_STATUS(portnum),
250 intstat & 0x000700bd);
251
252 return 0;
253}
254
058f88d6
AB
255static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum)
256{
257 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
258 rdev->rswitch->add_entry = tsi57x_route_add_entry;
259 rdev->rswitch->get_entry = tsi57x_route_get_entry;
260 rdev->rswitch->clr_table = tsi57x_route_clr_table;
261 rdev->rswitch->em_init = tsi57x_em_init;
262 rdev->rswitch->em_handle = tsi57x_em_handler;
263
264 return 0;
265}
266
267DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_switch_init);
268DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_switch_init);
269DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_switch_init);
270DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_switch_init);