18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * RapidIO Tsi57x switch family support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2009-2010 Integrated Device Technology, Inc. 68c2ecf20Sopenharmony_ci * Alexandre Bounine <alexandre.bounine@idt.com> 78c2ecf20Sopenharmony_ci * - Added EM support 88c2ecf20Sopenharmony_ci * - Modified switch operations initialization. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright 2005 MontaVista Software, Inc. 118c2ecf20Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/rio.h> 158c2ecf20Sopenharmony_ci#include <linux/rio_drv.h> 168c2ecf20Sopenharmony_ci#include <linux/rio_ids.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include "../rio.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Global (broadcast) route registers */ 228c2ecf20Sopenharmony_ci#define SPBC_ROUTE_CFG_DESTID 0x10070 238c2ecf20Sopenharmony_ci#define SPBC_ROUTE_CFG_PORT 0x10074 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Per port route registers */ 268c2ecf20Sopenharmony_ci#define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n) 278c2ecf20Sopenharmony_ci#define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define TSI578_SP_MODE(n) (0x11004 + n*0x100) 308c2ecf20Sopenharmony_ci#define TSI578_SP_MODE_GLBL 0x10004 318c2ecf20Sopenharmony_ci#define TSI578_SP_MODE_PW_DIS 0x08000000 328c2ecf20Sopenharmony_ci#define TSI578_SP_MODE_LUT_512 0x01000000 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100) 358c2ecf20Sopenharmony_ci#define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100) 368c2ecf20Sopenharmony_ci#define TSI578_SP_CS_TX(n) (0x13014 + n*0x100) 378c2ecf20Sopenharmony_ci#define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define TSI578_GLBL_ROUTE_BASE 0x10078 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int 428c2ecf20Sopenharmony_citsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 438c2ecf20Sopenharmony_ci u16 table, u16 route_destid, u8 route_port) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (table == RIO_GLOBAL_TABLE) { 468c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 478c2ecf20Sopenharmony_ci SPBC_ROUTE_CFG_DESTID, route_destid); 488c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 498c2ecf20Sopenharmony_ci SPBC_ROUTE_CFG_PORT, route_port); 508c2ecf20Sopenharmony_ci } else { 518c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 528c2ecf20Sopenharmony_ci SPP_ROUTE_CFG_DESTID(table), route_destid); 538c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 548c2ecf20Sopenharmony_ci SPP_ROUTE_CFG_PORT(table), route_port); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci udelay(10); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int 638c2ecf20Sopenharmony_citsi57x_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 648c2ecf20Sopenharmony_ci u16 table, u16 route_destid, u8 *route_port) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci int ret = 0; 678c2ecf20Sopenharmony_ci u32 result; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (table == RIO_GLOBAL_TABLE) { 708c2ecf20Sopenharmony_ci /* Use local RT of the ingress port to avoid possible 718c2ecf20Sopenharmony_ci race condition */ 728c2ecf20Sopenharmony_ci rio_mport_read_config_32(mport, destid, hopcount, 738c2ecf20Sopenharmony_ci RIO_SWP_INFO_CAR, &result); 748c2ecf20Sopenharmony_ci table = (result & RIO_SWP_INFO_PORT_NUM_MASK); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 788c2ecf20Sopenharmony_ci SPP_ROUTE_CFG_DESTID(table), route_destid); 798c2ecf20Sopenharmony_ci rio_mport_read_config_32(mport, destid, hopcount, 808c2ecf20Sopenharmony_ci SPP_ROUTE_CFG_PORT(table), &result); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci *route_port = (u8)result; 838c2ecf20Sopenharmony_ci if (*route_port > 15) 848c2ecf20Sopenharmony_ci ret = -1; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int 908c2ecf20Sopenharmony_citsi57x_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 918c2ecf20Sopenharmony_ci u16 table) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci u32 route_idx; 948c2ecf20Sopenharmony_ci u32 lut_size; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci lut_size = (mport->sys_size) ? 0x1ff : 0xff; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (table == RIO_GLOBAL_TABLE) { 998c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 1008c2ecf20Sopenharmony_ci SPBC_ROUTE_CFG_DESTID, 0x80000000); 1018c2ecf20Sopenharmony_ci for (route_idx = 0; route_idx <= lut_size; route_idx++) 1028c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 1038c2ecf20Sopenharmony_ci SPBC_ROUTE_CFG_PORT, 1048c2ecf20Sopenharmony_ci RIO_INVALID_ROUTE); 1058c2ecf20Sopenharmony_ci } else { 1068c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 1078c2ecf20Sopenharmony_ci SPP_ROUTE_CFG_DESTID(table), 0x80000000); 1088c2ecf20Sopenharmony_ci for (route_idx = 0; route_idx <= lut_size; route_idx++) 1098c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 1108c2ecf20Sopenharmony_ci SPP_ROUTE_CFG_PORT(table) , RIO_INVALID_ROUTE); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int 1178c2ecf20Sopenharmony_citsi57x_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, 1188c2ecf20Sopenharmony_ci u8 sw_domain) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci u32 regval; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * Switch domain configuration operates only at global level 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* Turn off flat (LUT_512) mode */ 1278c2ecf20Sopenharmony_ci rio_mport_read_config_32(mport, destid, hopcount, 1288c2ecf20Sopenharmony_ci TSI578_SP_MODE_GLBL, ®val); 1298c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, TSI578_SP_MODE_GLBL, 1308c2ecf20Sopenharmony_ci regval & ~TSI578_SP_MODE_LUT_512); 1318c2ecf20Sopenharmony_ci /* Set switch domain base */ 1328c2ecf20Sopenharmony_ci rio_mport_write_config_32(mport, destid, hopcount, 1338c2ecf20Sopenharmony_ci TSI578_GLBL_ROUTE_BASE, 1348c2ecf20Sopenharmony_ci (u32)(sw_domain << 24)); 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int 1398c2ecf20Sopenharmony_citsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, 1408c2ecf20Sopenharmony_ci u8 *sw_domain) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci u32 regval; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* 1458c2ecf20Sopenharmony_ci * Switch domain configuration operates only at global level 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci rio_mport_read_config_32(mport, destid, hopcount, 1488c2ecf20Sopenharmony_ci TSI578_GLBL_ROUTE_BASE, ®val); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci *sw_domain = (u8)(regval >> 24); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int 1568c2ecf20Sopenharmony_citsi57x_em_init(struct rio_dev *rdev) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci u32 regval; 1598c2ecf20Sopenharmony_ci int portnum; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci pr_debug("TSI578 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci for (portnum = 0; 1648c2ecf20Sopenharmony_ci portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) { 1658c2ecf20Sopenharmony_ci /* Make sure that Port-Writes are enabled (for all ports) */ 1668c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 1678c2ecf20Sopenharmony_ci TSI578_SP_MODE(portnum), ®val); 1688c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 1698c2ecf20Sopenharmony_ci TSI578_SP_MODE(portnum), 1708c2ecf20Sopenharmony_ci regval & ~TSI578_SP_MODE_PW_DIS); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Clear all pending interrupts */ 1738c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 1748c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 1758c2ecf20Sopenharmony_ci ®val); 1768c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 1778c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 1788c2ecf20Sopenharmony_ci regval & 0x07120214); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 1818c2ecf20Sopenharmony_ci TSI578_SP_INT_STATUS(portnum), ®val); 1828c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 1838c2ecf20Sopenharmony_ci TSI578_SP_INT_STATUS(portnum), 1848c2ecf20Sopenharmony_ci regval & 0x000700bd); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Enable all interrupts to allow ports to send a port-write */ 1878c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 1888c2ecf20Sopenharmony_ci TSI578_SP_CTL_INDEP(portnum), ®val); 1898c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 1908c2ecf20Sopenharmony_ci TSI578_SP_CTL_INDEP(portnum), 1918c2ecf20Sopenharmony_ci regval | 0x000b0000); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Skip next (odd) port if the current port is in x4 mode */ 1948c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 1958c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_CTL_CSR(rdev, portnum), 1968c2ecf20Sopenharmony_ci ®val); 1978c2ecf20Sopenharmony_ci if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4) 1988c2ecf20Sopenharmony_ci portnum++; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* set TVAL = ~50us */ 2028c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 2038c2ecf20Sopenharmony_ci rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int 2098c2ecf20Sopenharmony_citsi57x_em_handler(struct rio_dev *rdev, u8 portnum) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct rio_mport *mport = rdev->net->hport; 2128c2ecf20Sopenharmony_ci u32 intstat, err_status; 2138c2ecf20Sopenharmony_ci int sendcount, checkcount; 2148c2ecf20Sopenharmony_ci u8 route_port; 2158c2ecf20Sopenharmony_ci u32 regval; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 2188c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 2198c2ecf20Sopenharmony_ci &err_status); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) && 2228c2ecf20Sopenharmony_ci (err_status & (RIO_PORT_N_ERR_STS_OUT_ES | 2238c2ecf20Sopenharmony_ci RIO_PORT_N_ERR_STS_INP_ES))) { 2248c2ecf20Sopenharmony_ci /* Remove any queued packets by locking/unlocking port */ 2258c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 2268c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_CTL_CSR(rdev, portnum), 2278c2ecf20Sopenharmony_ci ®val); 2288c2ecf20Sopenharmony_ci if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) { 2298c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 2308c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_CTL_CSR(rdev, portnum), 2318c2ecf20Sopenharmony_ci regval | RIO_PORT_N_CTL_LOCKOUT); 2328c2ecf20Sopenharmony_ci udelay(50); 2338c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 2348c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_CTL_CSR(rdev, portnum), 2358c2ecf20Sopenharmony_ci regval); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Read from link maintenance response register to clear 2398c2ecf20Sopenharmony_ci * valid bit 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 2428c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, portnum), 2438c2ecf20Sopenharmony_ci ®val); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Send a Packet-Not-Accepted/Link-Request-Input-Status control 2468c2ecf20Sopenharmony_ci * symbol to recover from IES/OES 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci sendcount = 3; 2498c2ecf20Sopenharmony_ci while (sendcount) { 2508c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 2518c2ecf20Sopenharmony_ci TSI578_SP_CS_TX(portnum), 0x40fc8000); 2528c2ecf20Sopenharmony_ci checkcount = 3; 2538c2ecf20Sopenharmony_ci while (checkcount--) { 2548c2ecf20Sopenharmony_ci udelay(50); 2558c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 2568c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, 2578c2ecf20Sopenharmony_ci portnum), 2588c2ecf20Sopenharmony_ci ®val); 2598c2ecf20Sopenharmony_ci if (regval & RIO_PORT_N_MNT_RSP_RVAL) 2608c2ecf20Sopenharmony_ci goto exit_es; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci sendcount--; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ciexit_es: 2688c2ecf20Sopenharmony_ci /* Clear implementation specific error status bits */ 2698c2ecf20Sopenharmony_ci rio_read_config_32(rdev, TSI578_SP_INT_STATUS(portnum), &intstat); 2708c2ecf20Sopenharmony_ci pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n", 2718c2ecf20Sopenharmony_ci rdev->destid, rdev->hopcount, portnum, intstat); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (intstat & 0x10000) { 2748c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 2758c2ecf20Sopenharmony_ci TSI578_SP_LUT_PEINF(portnum), ®val); 2768c2ecf20Sopenharmony_ci regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24); 2778c2ecf20Sopenharmony_ci route_port = rdev->rswitch->route_table[regval]; 2788c2ecf20Sopenharmony_ci pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n", 2798c2ecf20Sopenharmony_ci rio_name(rdev), portnum, regval); 2808c2ecf20Sopenharmony_ci tsi57x_route_add_entry(mport, rdev->destid, rdev->hopcount, 2818c2ecf20Sopenharmony_ci RIO_GLOBAL_TABLE, regval, route_port); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci rio_write_config_32(rdev, TSI578_SP_INT_STATUS(portnum), 2858c2ecf20Sopenharmony_ci intstat & 0x000700bd); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic struct rio_switch_ops tsi57x_switch_ops = { 2918c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2928c2ecf20Sopenharmony_ci .add_entry = tsi57x_route_add_entry, 2938c2ecf20Sopenharmony_ci .get_entry = tsi57x_route_get_entry, 2948c2ecf20Sopenharmony_ci .clr_table = tsi57x_route_clr_table, 2958c2ecf20Sopenharmony_ci .set_domain = tsi57x_set_domain, 2968c2ecf20Sopenharmony_ci .get_domain = tsi57x_get_domain, 2978c2ecf20Sopenharmony_ci .em_init = tsi57x_em_init, 2988c2ecf20Sopenharmony_ci .em_handle = tsi57x_em_handler, 2998c2ecf20Sopenharmony_ci}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int tsi57x_probe(struct rio_dev *rdev, const struct rio_device_id *id) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci spin_lock(&rdev->rswitch->lock); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (rdev->rswitch->ops) { 3088c2ecf20Sopenharmony_ci spin_unlock(&rdev->rswitch->lock); 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci rdev->rswitch->ops = &tsi57x_switch_ops; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (rdev->do_enum) { 3148c2ecf20Sopenharmony_ci /* Ensure that default routing is disabled on startup */ 3158c2ecf20Sopenharmony_ci rio_write_config_32(rdev, RIO_STD_RTE_DEFAULT_PORT, 3168c2ecf20Sopenharmony_ci RIO_INVALID_ROUTE); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci spin_unlock(&rdev->rswitch->lock); 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void tsi57x_remove(struct rio_dev *rdev) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 3268c2ecf20Sopenharmony_ci spin_lock(&rdev->rswitch->lock); 3278c2ecf20Sopenharmony_ci if (rdev->rswitch->ops != &tsi57x_switch_ops) { 3288c2ecf20Sopenharmony_ci spin_unlock(&rdev->rswitch->lock); 3298c2ecf20Sopenharmony_ci return; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci rdev->rswitch->ops = NULL; 3328c2ecf20Sopenharmony_ci spin_unlock(&rdev->rswitch->lock); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic const struct rio_device_id tsi57x_id_table[] = { 3368c2ecf20Sopenharmony_ci {RIO_DEVICE(RIO_DID_TSI572, RIO_VID_TUNDRA)}, 3378c2ecf20Sopenharmony_ci {RIO_DEVICE(RIO_DID_TSI574, RIO_VID_TUNDRA)}, 3388c2ecf20Sopenharmony_ci {RIO_DEVICE(RIO_DID_TSI577, RIO_VID_TUNDRA)}, 3398c2ecf20Sopenharmony_ci {RIO_DEVICE(RIO_DID_TSI578, RIO_VID_TUNDRA)}, 3408c2ecf20Sopenharmony_ci { 0, } /* terminate list */ 3418c2ecf20Sopenharmony_ci}; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic struct rio_driver tsi57x_driver = { 3448c2ecf20Sopenharmony_ci .name = "tsi57x", 3458c2ecf20Sopenharmony_ci .id_table = tsi57x_id_table, 3468c2ecf20Sopenharmony_ci .probe = tsi57x_probe, 3478c2ecf20Sopenharmony_ci .remove = tsi57x_remove, 3488c2ecf20Sopenharmony_ci}; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int __init tsi57x_init(void) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci return rio_register_driver(&tsi57x_driver); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void __exit tsi57x_exit(void) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci rio_unregister_driver(&tsi57x_driver); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cidevice_initcall(tsi57x_init); 3618c2ecf20Sopenharmony_cimodule_exit(tsi57x_exit); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IDT Tsi57x Serial RapidIO switch family driver"); 3648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Integrated Device Technology, Inc."); 3658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 366