1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * RapidIO Tsi57x switch family support 4 * 5 * Copyright 2009-2010 Integrated Device Technology, Inc. 6 * Alexandre Bounine <alexandre.bounine@idt.com> 7 * - Added EM support 8 * - Modified switch operations initialization. 9 * 10 * Copyright 2005 MontaVista Software, Inc. 11 * Matt Porter <mporter@kernel.crashing.org> 12 */ 13 14#include <linux/rio.h> 15#include <linux/rio_drv.h> 16#include <linux/rio_ids.h> 17#include <linux/delay.h> 18#include <linux/module.h> 19#include "../rio.h" 20 21/* Global (broadcast) route registers */ 22#define SPBC_ROUTE_CFG_DESTID 0x10070 23#define SPBC_ROUTE_CFG_PORT 0x10074 24 25/* Per port route registers */ 26#define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n) 27#define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n) 28 29#define TSI578_SP_MODE(n) (0x11004 + n*0x100) 30#define TSI578_SP_MODE_GLBL 0x10004 31#define TSI578_SP_MODE_PW_DIS 0x08000000 32#define TSI578_SP_MODE_LUT_512 0x01000000 33 34#define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100) 35#define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100) 36#define TSI578_SP_CS_TX(n) (0x13014 + n*0x100) 37#define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100) 38 39#define TSI578_GLBL_ROUTE_BASE 0x10078 40 41static int 42tsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 43 u16 table, u16 route_destid, u8 route_port) 44{ 45 if (table == RIO_GLOBAL_TABLE) { 46 rio_mport_write_config_32(mport, destid, hopcount, 47 SPBC_ROUTE_CFG_DESTID, route_destid); 48 rio_mport_write_config_32(mport, destid, hopcount, 49 SPBC_ROUTE_CFG_PORT, route_port); 50 } else { 51 rio_mport_write_config_32(mport, destid, hopcount, 52 SPP_ROUTE_CFG_DESTID(table), route_destid); 53 rio_mport_write_config_32(mport, destid, hopcount, 54 SPP_ROUTE_CFG_PORT(table), route_port); 55 } 56 57 udelay(10); 58 59 return 0; 60} 61 62static int 63tsi57x_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 64 u16 table, u16 route_destid, u8 *route_port) 65{ 66 int ret = 0; 67 u32 result; 68 69 if (table == RIO_GLOBAL_TABLE) { 70 /* Use local RT of the ingress port to avoid possible 71 race condition */ 72 rio_mport_read_config_32(mport, destid, hopcount, 73 RIO_SWP_INFO_CAR, &result); 74 table = (result & RIO_SWP_INFO_PORT_NUM_MASK); 75 } 76 77 rio_mport_write_config_32(mport, destid, hopcount, 78 SPP_ROUTE_CFG_DESTID(table), route_destid); 79 rio_mport_read_config_32(mport, destid, hopcount, 80 SPP_ROUTE_CFG_PORT(table), &result); 81 82 *route_port = (u8)result; 83 if (*route_port > 15) 84 ret = -1; 85 86 return ret; 87} 88 89static int 90tsi57x_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 91 u16 table) 92{ 93 u32 route_idx; 94 u32 lut_size; 95 96 lut_size = (mport->sys_size) ? 0x1ff : 0xff; 97 98 if (table == RIO_GLOBAL_TABLE) { 99 rio_mport_write_config_32(mport, destid, hopcount, 100 SPBC_ROUTE_CFG_DESTID, 0x80000000); 101 for (route_idx = 0; route_idx <= lut_size; route_idx++) 102 rio_mport_write_config_32(mport, destid, hopcount, 103 SPBC_ROUTE_CFG_PORT, 104 RIO_INVALID_ROUTE); 105 } else { 106 rio_mport_write_config_32(mport, destid, hopcount, 107 SPP_ROUTE_CFG_DESTID(table), 0x80000000); 108 for (route_idx = 0; route_idx <= lut_size; route_idx++) 109 rio_mport_write_config_32(mport, destid, hopcount, 110 SPP_ROUTE_CFG_PORT(table) , RIO_INVALID_ROUTE); 111 } 112 113 return 0; 114} 115 116static int 117tsi57x_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, 118 u8 sw_domain) 119{ 120 u32 regval; 121 122 /* 123 * Switch domain configuration operates only at global level 124 */ 125 126 /* Turn off flat (LUT_512) mode */ 127 rio_mport_read_config_32(mport, destid, hopcount, 128 TSI578_SP_MODE_GLBL, ®val); 129 rio_mport_write_config_32(mport, destid, hopcount, TSI578_SP_MODE_GLBL, 130 regval & ~TSI578_SP_MODE_LUT_512); 131 /* Set switch domain base */ 132 rio_mport_write_config_32(mport, destid, hopcount, 133 TSI578_GLBL_ROUTE_BASE, 134 (u32)(sw_domain << 24)); 135 return 0; 136} 137 138static int 139tsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, 140 u8 *sw_domain) 141{ 142 u32 regval; 143 144 /* 145 * Switch domain configuration operates only at global level 146 */ 147 rio_mport_read_config_32(mport, destid, hopcount, 148 TSI578_GLBL_ROUTE_BASE, ®val); 149 150 *sw_domain = (u8)(regval >> 24); 151 152 return 0; 153} 154 155static int 156tsi57x_em_init(struct rio_dev *rdev) 157{ 158 u32 regval; 159 int portnum; 160 161 pr_debug("TSI578 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); 162 163 for (portnum = 0; 164 portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) { 165 /* Make sure that Port-Writes are enabled (for all ports) */ 166 rio_read_config_32(rdev, 167 TSI578_SP_MODE(portnum), ®val); 168 rio_write_config_32(rdev, 169 TSI578_SP_MODE(portnum), 170 regval & ~TSI578_SP_MODE_PW_DIS); 171 172 /* Clear all pending interrupts */ 173 rio_read_config_32(rdev, 174 RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 175 ®val); 176 rio_write_config_32(rdev, 177 RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 178 regval & 0x07120214); 179 180 rio_read_config_32(rdev, 181 TSI578_SP_INT_STATUS(portnum), ®val); 182 rio_write_config_32(rdev, 183 TSI578_SP_INT_STATUS(portnum), 184 regval & 0x000700bd); 185 186 /* Enable all interrupts to allow ports to send a port-write */ 187 rio_read_config_32(rdev, 188 TSI578_SP_CTL_INDEP(portnum), ®val); 189 rio_write_config_32(rdev, 190 TSI578_SP_CTL_INDEP(portnum), 191 regval | 0x000b0000); 192 193 /* Skip next (odd) port if the current port is in x4 mode */ 194 rio_read_config_32(rdev, 195 RIO_DEV_PORT_N_CTL_CSR(rdev, portnum), 196 ®val); 197 if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4) 198 portnum++; 199 } 200 201 /* set TVAL = ~50us */ 202 rio_write_config_32(rdev, 203 rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8); 204 205 return 0; 206} 207 208static int 209tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) 210{ 211 struct rio_mport *mport = rdev->net->hport; 212 u32 intstat, err_status; 213 int sendcount, checkcount; 214 u8 route_port; 215 u32 regval; 216 217 rio_read_config_32(rdev, 218 RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 219 &err_status); 220 221 if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) && 222 (err_status & (RIO_PORT_N_ERR_STS_OUT_ES | 223 RIO_PORT_N_ERR_STS_INP_ES))) { 224 /* Remove any queued packets by locking/unlocking port */ 225 rio_read_config_32(rdev, 226 RIO_DEV_PORT_N_CTL_CSR(rdev, portnum), 227 ®val); 228 if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) { 229 rio_write_config_32(rdev, 230 RIO_DEV_PORT_N_CTL_CSR(rdev, portnum), 231 regval | RIO_PORT_N_CTL_LOCKOUT); 232 udelay(50); 233 rio_write_config_32(rdev, 234 RIO_DEV_PORT_N_CTL_CSR(rdev, portnum), 235 regval); 236 } 237 238 /* Read from link maintenance response register to clear 239 * valid bit 240 */ 241 rio_read_config_32(rdev, 242 RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, portnum), 243 ®val); 244 245 /* Send a Packet-Not-Accepted/Link-Request-Input-Status control 246 * symbol to recover from IES/OES 247 */ 248 sendcount = 3; 249 while (sendcount) { 250 rio_write_config_32(rdev, 251 TSI578_SP_CS_TX(portnum), 0x40fc8000); 252 checkcount = 3; 253 while (checkcount--) { 254 udelay(50); 255 rio_read_config_32(rdev, 256 RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, 257 portnum), 258 ®val); 259 if (regval & RIO_PORT_N_MNT_RSP_RVAL) 260 goto exit_es; 261 } 262 263 sendcount--; 264 } 265 } 266 267exit_es: 268 /* Clear implementation specific error status bits */ 269 rio_read_config_32(rdev, TSI578_SP_INT_STATUS(portnum), &intstat); 270 pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n", 271 rdev->destid, rdev->hopcount, portnum, intstat); 272 273 if (intstat & 0x10000) { 274 rio_read_config_32(rdev, 275 TSI578_SP_LUT_PEINF(portnum), ®val); 276 regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24); 277 route_port = rdev->rswitch->route_table[regval]; 278 pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n", 279 rio_name(rdev), portnum, regval); 280 tsi57x_route_add_entry(mport, rdev->destid, rdev->hopcount, 281 RIO_GLOBAL_TABLE, regval, route_port); 282 } 283 284 rio_write_config_32(rdev, TSI578_SP_INT_STATUS(portnum), 285 intstat & 0x000700bd); 286 287 return 0; 288} 289 290static struct rio_switch_ops tsi57x_switch_ops = { 291 .owner = THIS_MODULE, 292 .add_entry = tsi57x_route_add_entry, 293 .get_entry = tsi57x_route_get_entry, 294 .clr_table = tsi57x_route_clr_table, 295 .set_domain = tsi57x_set_domain, 296 .get_domain = tsi57x_get_domain, 297 .em_init = tsi57x_em_init, 298 .em_handle = tsi57x_em_handler, 299}; 300 301static int tsi57x_probe(struct rio_dev *rdev, const struct rio_device_id *id) 302{ 303 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 304 305 spin_lock(&rdev->rswitch->lock); 306 307 if (rdev->rswitch->ops) { 308 spin_unlock(&rdev->rswitch->lock); 309 return -EINVAL; 310 } 311 rdev->rswitch->ops = &tsi57x_switch_ops; 312 313 if (rdev->do_enum) { 314 /* Ensure that default routing is disabled on startup */ 315 rio_write_config_32(rdev, RIO_STD_RTE_DEFAULT_PORT, 316 RIO_INVALID_ROUTE); 317 } 318 319 spin_unlock(&rdev->rswitch->lock); 320 return 0; 321} 322 323static void tsi57x_remove(struct rio_dev *rdev) 324{ 325 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 326 spin_lock(&rdev->rswitch->lock); 327 if (rdev->rswitch->ops != &tsi57x_switch_ops) { 328 spin_unlock(&rdev->rswitch->lock); 329 return; 330 } 331 rdev->rswitch->ops = NULL; 332 spin_unlock(&rdev->rswitch->lock); 333} 334 335static const struct rio_device_id tsi57x_id_table[] = { 336 {RIO_DEVICE(RIO_DID_TSI572, RIO_VID_TUNDRA)}, 337 {RIO_DEVICE(RIO_DID_TSI574, RIO_VID_TUNDRA)}, 338 {RIO_DEVICE(RIO_DID_TSI577, RIO_VID_TUNDRA)}, 339 {RIO_DEVICE(RIO_DID_TSI578, RIO_VID_TUNDRA)}, 340 { 0, } /* terminate list */ 341}; 342 343static struct rio_driver tsi57x_driver = { 344 .name = "tsi57x", 345 .id_table = tsi57x_id_table, 346 .probe = tsi57x_probe, 347 .remove = tsi57x_remove, 348}; 349 350static int __init tsi57x_init(void) 351{ 352 return rio_register_driver(&tsi57x_driver); 353} 354 355static void __exit tsi57x_exit(void) 356{ 357 rio_unregister_driver(&tsi57x_driver); 358} 359 360device_initcall(tsi57x_init); 361module_exit(tsi57x_exit); 362 363MODULE_DESCRIPTION("IDT Tsi57x Serial RapidIO switch family driver"); 364MODULE_AUTHOR("Integrated Device Technology, Inc."); 365MODULE_LICENSE("GPL"); 366