2 * RapidIO Tsi57x switch family support
4 * Copyright 2009 Integrated Device Technology, Inc.
5 * Copyright 2005 MontaVista Software, Inc.
6 * Matt Porter <mporter@kernel.crashing.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
14 #include <linux/rio.h>
15 #include <linux/rio_drv.h>
16 #include <linux/rio_ids.h>
17 #include <linux/delay.h>
20 /* Global (broadcast) route registers */
21 #define SPBC_ROUTE_CFG_DESTID 0x10070
22 #define SPBC_ROUTE_CFG_PORT 0x10074
24 /* Per port route registers */
25 #define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n)
26 #define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n)
28 #define TSI578_SP_MODE(n) (0x11004 + n*0x100)
29 #define TSI578_SP_MODE_PW_DIS 0x08000000
31 #define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100)
32 #define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100)
33 #define TSI578_SP_CS_TX(n) (0x13014 + n*0x100)
34 #define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100)
37 tsi57x_route_add_entry(struct rio_mport
*mport
, u16 destid
, u8 hopcount
,
38 u16 table
, u16 route_destid
, u8 route_port
)
40 if (table
== RIO_GLOBAL_TABLE
) {
41 rio_mport_write_config_32(mport
, destid
, hopcount
,
42 SPBC_ROUTE_CFG_DESTID
, route_destid
);
43 rio_mport_write_config_32(mport
, destid
, hopcount
,
44 SPBC_ROUTE_CFG_PORT
, route_port
);
46 rio_mport_write_config_32(mport
, destid
, hopcount
,
47 SPP_ROUTE_CFG_DESTID(table
), route_destid
);
48 rio_mport_write_config_32(mport
, destid
, hopcount
,
49 SPP_ROUTE_CFG_PORT(table
), route_port
);
58 tsi57x_route_get_entry(struct rio_mport
*mport
, u16 destid
, u8 hopcount
,
59 u16 table
, u16 route_destid
, u8
*route_port
)
64 if (table
== RIO_GLOBAL_TABLE
) {
65 /* Use local RT of the ingress port to avoid possible
67 rio_mport_read_config_32(mport
, destid
, hopcount
,
68 RIO_SWP_INFO_CAR
, &result
);
69 table
= (result
& RIO_SWP_INFO_PORT_NUM_MASK
);
72 rio_mport_write_config_32(mport
, destid
, hopcount
,
73 SPP_ROUTE_CFG_DESTID(table
), route_destid
);
74 rio_mport_read_config_32(mport
, destid
, hopcount
,
75 SPP_ROUTE_CFG_PORT(table
), &result
);
77 *route_port
= (u8
)result
;
85 tsi57x_route_clr_table(struct rio_mport
*mport
, u16 destid
, u8 hopcount
,
91 lut_size
= (mport
->sys_size
) ? 0x1ff : 0xff;
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
,
101 rio_mport_write_config_32(mport
, destid
, hopcount
,
102 SPP_ROUTE_CFG_DESTID(table
), 0x80000000);
103 for (route_idx
= 0; route_idx
<= lut_size
; route_idx
++)
104 rio_mport_write_config_32(mport
, destid
, hopcount
,
105 SPP_ROUTE_CFG_PORT(table
) , RIO_INVALID_ROUTE
);
111 DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA
, RIO_DID_TSI572
, tsi57x_route_add_entry
, tsi57x_route_get_entry
, tsi57x_route_clr_table
);
112 DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA
, RIO_DID_TSI574
, tsi57x_route_add_entry
, tsi57x_route_get_entry
, tsi57x_route_clr_table
);
113 DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA
, RIO_DID_TSI577
, tsi57x_route_add_entry
, tsi57x_route_get_entry
, tsi57x_route_clr_table
);
114 DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA
, RIO_DID_TSI578
, tsi57x_route_add_entry
, tsi57x_route_get_entry
, tsi57x_route_clr_table
);
117 tsi57x_em_init(struct rio_dev
*rdev
)
119 struct rio_mport
*mport
= rdev
->net
->hport
;
120 u16 destid
= rdev
->rswitch
->destid
;
121 u8 hopcount
= rdev
->rswitch
->hopcount
;
125 pr_debug("TSI578 %s [%d:%d]\n", __func__
, destid
, hopcount
);
127 for (portnum
= 0; portnum
< 16; portnum
++) {
128 /* Make sure that Port-Writes are enabled (for all ports) */
129 rio_mport_read_config_32(mport
, destid
, hopcount
,
130 TSI578_SP_MODE(portnum
), ®val
);
131 rio_mport_write_config_32(mport
, destid
, hopcount
,
132 TSI578_SP_MODE(portnum
),
133 regval
& ~TSI578_SP_MODE_PW_DIS
);
135 /* Clear all pending interrupts */
136 rio_mport_read_config_32(mport
, destid
, hopcount
,
138 RIO_PORT_N_ERR_STS_CSR(portnum
),
140 rio_mport_write_config_32(mport
, destid
, hopcount
,
142 RIO_PORT_N_ERR_STS_CSR(portnum
),
143 regval
& 0x07120214);
145 rio_mport_read_config_32(mport
, destid
, hopcount
,
146 TSI578_SP_INT_STATUS(portnum
), ®val
);
147 rio_mport_write_config_32(mport
, destid
, hopcount
,
148 TSI578_SP_INT_STATUS(portnum
),
149 regval
& 0x000700bd);
151 /* Enable all interrupts to allow ports to send a port-write */
152 rio_mport_read_config_32(mport
, destid
, hopcount
,
153 TSI578_SP_CTL_INDEP(portnum
), ®val
);
154 rio_mport_write_config_32(mport
, destid
, hopcount
,
155 TSI578_SP_CTL_INDEP(portnum
),
156 regval
| 0x000b0000);
158 /* Skip next (odd) port if the current port is in x4 mode */
159 rio_mport_read_config_32(mport
, destid
, hopcount
,
160 rdev
->phys_efptr
+ RIO_PORT_N_CTL_CSR(portnum
),
162 if ((regval
& RIO_PORT_N_CTL_PWIDTH
) == RIO_PORT_N_CTL_PWIDTH_4
)
170 tsi57x_em_handler(struct rio_dev
*rdev
, u8 portnum
)
172 struct rio_mport
*mport
= rdev
->net
->hport
;
173 u16 destid
= rdev
->rswitch
->destid
;
174 u8 hopcount
= rdev
->rswitch
->hopcount
;
175 u32 intstat
, err_status
;
176 int sendcount
, checkcount
;
180 rio_mport_read_config_32(mport
, destid
, hopcount
,
181 rdev
->phys_efptr
+ RIO_PORT_N_ERR_STS_CSR(portnum
),
184 if ((err_status
& RIO_PORT_N_ERR_STS_PORT_OK
) &&
185 (err_status
& (RIO_PORT_N_ERR_STS_PW_OUT_ES
|
186 RIO_PORT_N_ERR_STS_PW_INP_ES
))) {
187 /* Remove any queued packets by locking/unlocking port */
188 rio_mport_read_config_32(mport
, destid
, hopcount
,
189 rdev
->phys_efptr
+ RIO_PORT_N_CTL_CSR(portnum
),
191 if (!(regval
& RIO_PORT_N_CTL_LOCKOUT
)) {
192 rio_mport_write_config_32(mport
, destid
, hopcount
,
193 rdev
->phys_efptr
+ RIO_PORT_N_CTL_CSR(portnum
),
194 regval
| RIO_PORT_N_CTL_LOCKOUT
);
196 rio_mport_write_config_32(mport
, destid
, hopcount
,
197 rdev
->phys_efptr
+ RIO_PORT_N_CTL_CSR(portnum
),
201 /* Read from link maintenance response register to clear
204 rio_mport_read_config_32(mport
, destid
, hopcount
,
205 rdev
->phys_efptr
+ RIO_PORT_N_MNT_RSP_CSR(portnum
),
208 /* Send a Packet-Not-Accepted/Link-Request-Input-Status control
209 * symbol to recover from IES/OES
213 rio_mport_write_config_32(mport
, destid
, hopcount
,
214 TSI578_SP_CS_TX(portnum
), 0x40fc8000);
216 while (checkcount
--) {
218 rio_mport_read_config_32(
219 mport
, destid
, hopcount
,
221 RIO_PORT_N_MNT_RSP_CSR(portnum
),
223 if (regval
& RIO_PORT_N_MNT_RSP_RVAL
)
232 /* Clear implementation specific error status bits */
233 rio_mport_read_config_32(mport
, destid
, hopcount
,
234 TSI578_SP_INT_STATUS(portnum
), &intstat
);
235 pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n",
236 destid
, hopcount
, portnum
, intstat
);
238 if (intstat
& 0x10000) {
239 rio_mport_read_config_32(mport
, destid
, hopcount
,
240 TSI578_SP_LUT_PEINF(portnum
), ®val
);
241 regval
= (mport
->sys_size
) ? (regval
>> 16) : (regval
>> 24);
242 route_port
= rdev
->rswitch
->route_table
[regval
];
243 pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n",
244 rio_name(rdev
), portnum
, regval
);
245 tsi57x_route_add_entry(mport
, destid
, hopcount
,
246 RIO_GLOBAL_TABLE
, regval
, route_port
);
249 rio_mport_write_config_32(mport
, destid
, hopcount
,
250 TSI578_SP_INT_STATUS(portnum
),
251 intstat
& 0x000700bd);
256 DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA
, RIO_DID_TSI572
, tsi57x_em_init
, tsi57x_em_handler
);
257 DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA
, RIO_DID_TSI574
, tsi57x_em_init
, tsi57x_em_handler
);
258 DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA
, RIO_DID_TSI577
, tsi57x_em_init
, tsi57x_em_handler
);
259 DECLARE_RIO_EM_OPS(RIO_VID_TUNDRA
, RIO_DID_TSI578
, tsi57x_em_init
, tsi57x_em_handler
);