18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IDT RXS Gen.3 Serial RapidIO switch family support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2016 Integrated Device Technology, Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/stat.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/rio.h> 118c2ecf20Sopenharmony_ci#include <linux/rio_drv.h> 128c2ecf20Sopenharmony_ci#include <linux/rio_ids.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/page.h> 168c2ecf20Sopenharmony_ci#include "../rio.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define RIO_EM_PW_STAT 0x40020 198c2ecf20Sopenharmony_ci#define RIO_PW_CTL 0x40204 208c2ecf20Sopenharmony_ci#define RIO_PW_CTL_PW_TMR 0xffffff00 218c2ecf20Sopenharmony_ci#define RIO_PW_ROUTE 0x40208 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define RIO_EM_DEV_INT_EN 0x40030 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define RIO_PLM_SPx_IMP_SPEC_CTL(x) (0x10100 + (x)*0x100) 268c2ecf20Sopenharmony_ci#define RIO_PLM_SPx_IMP_SPEC_CTL_SOFT_RST 0x02000000 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define RIO_PLM_SPx_PW_EN(x) (0x10118 + (x)*0x100) 298c2ecf20Sopenharmony_ci#define RIO_PLM_SPx_PW_EN_OK2U 0x40000000 308c2ecf20Sopenharmony_ci#define RIO_PLM_SPx_PW_EN_LINIT 0x10000000 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define RIO_BC_L2_Gn_ENTRYx_CSR(n, x) (0x31000 + (n)*0x400 + (x)*0x4) 338c2ecf20Sopenharmony_ci#define RIO_SPx_L2_Gn_ENTRYy_CSR(x, n, y) \ 348c2ecf20Sopenharmony_ci (0x51000 + (x)*0x2000 + (n)*0x400 + (y)*0x4) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int 378c2ecf20Sopenharmony_ciidtg3_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 388c2ecf20Sopenharmony_ci u16 table, u16 route_destid, u8 route_port) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci u32 rval; 418c2ecf20Sopenharmony_ci u32 entry = route_port; 428c2ecf20Sopenharmony_ci int err = 0; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci pr_debug("RIO: %s t=0x%x did_%x to p_%x\n", 458c2ecf20Sopenharmony_ci __func__, table, route_destid, entry); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (route_destid > 0xFF) 488c2ecf20Sopenharmony_ci return -EINVAL; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (route_port == RIO_INVALID_ROUTE) 518c2ecf20Sopenharmony_ci entry = RIO_RT_ENTRY_DROP_PKT; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (table == RIO_GLOBAL_TABLE) { 548c2ecf20Sopenharmony_ci /* Use broadcast register to update all per-port tables */ 558c2ecf20Sopenharmony_ci err = rio_mport_write_config_32(mport, destid, hopcount, 568c2ecf20Sopenharmony_ci RIO_BC_L2_Gn_ENTRYx_CSR(0, route_destid), 578c2ecf20Sopenharmony_ci entry); 588c2ecf20Sopenharmony_ci return err; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* 628c2ecf20Sopenharmony_ci * Verify that specified port/table number is valid 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci err = rio_mport_read_config_32(mport, destid, hopcount, 658c2ecf20Sopenharmony_ci RIO_SWP_INFO_CAR, &rval); 668c2ecf20Sopenharmony_ci if (err) 678c2ecf20Sopenharmony_ci return err; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (table >= RIO_GET_TOTAL_PORTS(rval)) 708c2ecf20Sopenharmony_ci return -EINVAL; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci err = rio_mport_write_config_32(mport, destid, hopcount, 738c2ecf20Sopenharmony_ci RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, route_destid), 748c2ecf20Sopenharmony_ci entry); 758c2ecf20Sopenharmony_ci return err; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int 798c2ecf20Sopenharmony_ciidtg3_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 808c2ecf20Sopenharmony_ci u16 table, u16 route_destid, u8 *route_port) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci u32 rval; 838c2ecf20Sopenharmony_ci int err; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (route_destid > 0xFF) 868c2ecf20Sopenharmony_ci return -EINVAL; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci err = rio_mport_read_config_32(mport, destid, hopcount, 898c2ecf20Sopenharmony_ci RIO_SWP_INFO_CAR, &rval); 908c2ecf20Sopenharmony_ci if (err) 918c2ecf20Sopenharmony_ci return err; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* 948c2ecf20Sopenharmony_ci * This switch device does not have the dedicated global routing table. 958c2ecf20Sopenharmony_ci * It is substituted by reading routing table of the ingress port of 968c2ecf20Sopenharmony_ci * maintenance read requests. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if (table == RIO_GLOBAL_TABLE) 998c2ecf20Sopenharmony_ci table = RIO_GET_PORT_NUM(rval); 1008c2ecf20Sopenharmony_ci else if (table >= RIO_GET_TOTAL_PORTS(rval)) 1018c2ecf20Sopenharmony_ci return -EINVAL; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci err = rio_mport_read_config_32(mport, destid, hopcount, 1048c2ecf20Sopenharmony_ci RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, route_destid), 1058c2ecf20Sopenharmony_ci &rval); 1068c2ecf20Sopenharmony_ci if (err) 1078c2ecf20Sopenharmony_ci return err; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (rval == RIO_RT_ENTRY_DROP_PKT) 1108c2ecf20Sopenharmony_ci *route_port = RIO_INVALID_ROUTE; 1118c2ecf20Sopenharmony_ci else 1128c2ecf20Sopenharmony_ci *route_port = (u8)rval; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int 1188c2ecf20Sopenharmony_ciidtg3_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 1198c2ecf20Sopenharmony_ci u16 table) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci u32 i; 1228c2ecf20Sopenharmony_ci u32 rval; 1238c2ecf20Sopenharmony_ci int err; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (table == RIO_GLOBAL_TABLE) { 1268c2ecf20Sopenharmony_ci for (i = 0; i <= 0xff; i++) { 1278c2ecf20Sopenharmony_ci err = rio_mport_write_config_32(mport, destid, hopcount, 1288c2ecf20Sopenharmony_ci RIO_BC_L2_Gn_ENTRYx_CSR(0, i), 1298c2ecf20Sopenharmony_ci RIO_RT_ENTRY_DROP_PKT); 1308c2ecf20Sopenharmony_ci if (err) 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return err; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci err = rio_mport_read_config_32(mport, destid, hopcount, 1388c2ecf20Sopenharmony_ci RIO_SWP_INFO_CAR, &rval); 1398c2ecf20Sopenharmony_ci if (err) 1408c2ecf20Sopenharmony_ci return err; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (table >= RIO_GET_TOTAL_PORTS(rval)) 1438c2ecf20Sopenharmony_ci return -EINVAL; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci for (i = 0; i <= 0xff; i++) { 1468c2ecf20Sopenharmony_ci err = rio_mport_write_config_32(mport, destid, hopcount, 1478c2ecf20Sopenharmony_ci RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, i), 1488c2ecf20Sopenharmony_ci RIO_RT_ENTRY_DROP_PKT); 1498c2ecf20Sopenharmony_ci if (err) 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return err; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* 1578c2ecf20Sopenharmony_ci * This routine performs device-specific initialization only. 1588c2ecf20Sopenharmony_ci * All standard EM configuration should be performed at upper level. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_cistatic int 1618c2ecf20Sopenharmony_ciidtg3_em_init(struct rio_dev *rdev) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci int i, tmp; 1648c2ecf20Sopenharmony_ci u32 rval; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci pr_debug("RIO: %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Disable assertion of interrupt signal */ 1698c2ecf20Sopenharmony_ci rio_write_config_32(rdev, RIO_EM_DEV_INT_EN, 0); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Disable port-write event notifications during initialization */ 1728c2ecf20Sopenharmony_ci rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TX_CTRL, 1738c2ecf20Sopenharmony_ci RIO_EM_PW_TX_CTRL_PW_DIS); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Configure Port-Write notifications for hot-swap events */ 1768c2ecf20Sopenharmony_ci tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo); 1778c2ecf20Sopenharmony_ci for (i = 0; i < tmp; i++) { 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 1808c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_ERR_STS_CSR(rdev, i), 1818c2ecf20Sopenharmony_ci &rval); 1828c2ecf20Sopenharmony_ci if (rval & RIO_PORT_N_ERR_STS_PORT_UA) 1838c2ecf20Sopenharmony_ci continue; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* Clear events signaled before enabling notification */ 1868c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 1878c2ecf20Sopenharmony_ci rdev->em_efptr + RIO_EM_PN_ERR_DETECT(i), 0); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Enable event notifications */ 1908c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 1918c2ecf20Sopenharmony_ci rdev->em_efptr + RIO_EM_PN_ERRRATE_EN(i), 1928c2ecf20Sopenharmony_ci RIO_EM_PN_ERRRATE_EN_OK2U | RIO_EM_PN_ERRRATE_EN_U2OK); 1938c2ecf20Sopenharmony_ci /* Enable port-write generation on events */ 1948c2ecf20Sopenharmony_ci rio_write_config_32(rdev, RIO_PLM_SPx_PW_EN(i), 1958c2ecf20Sopenharmony_ci RIO_PLM_SPx_PW_EN_OK2U | RIO_PLM_SPx_PW_EN_LINIT); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Set Port-Write destination port */ 2008c2ecf20Sopenharmony_ci tmp = RIO_GET_PORT_NUM(rdev->swpinfo); 2018c2ecf20Sopenharmony_ci rio_write_config_32(rdev, RIO_PW_ROUTE, 1 << tmp); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Enable sending port-write event notifications */ 2058c2ecf20Sopenharmony_ci rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TX_CTRL, 0); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* set TVAL = ~50us */ 2088c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 2098c2ecf20Sopenharmony_ci rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* 2158c2ecf20Sopenharmony_ci * idtg3_em_handler - device-specific error handler 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * If the link is down (PORT_UNINIT) does nothing - this is considered 2188c2ecf20Sopenharmony_ci * as link partner removal from the port. 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * If the link is up (PORT_OK) - situation is handled as *new* device insertion. 2218c2ecf20Sopenharmony_ci * In this case ERR_STOP bits are cleared by issuing soft reset command to the 2228c2ecf20Sopenharmony_ci * reporting port. Inbound and outbound ackIDs are cleared by the reset as well. 2238c2ecf20Sopenharmony_ci * This way the port is synchronized with freshly inserted device (assuming it 2248c2ecf20Sopenharmony_ci * was reset/powered-up on insertion). 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * TODO: This is not sufficient in a situation when a link between two devices 2278c2ecf20Sopenharmony_ci * was down and up again (e.g. cable disconnect). For that situation full ackID 2288c2ecf20Sopenharmony_ci * realignment process has to be implemented. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistatic int 2318c2ecf20Sopenharmony_ciidtg3_em_handler(struct rio_dev *rdev, u8 pnum) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci u32 err_status; 2348c2ecf20Sopenharmony_ci u32 rval; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci rio_read_config_32(rdev, 2378c2ecf20Sopenharmony_ci RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum), 2388c2ecf20Sopenharmony_ci &err_status); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Do nothing for device/link removal */ 2418c2ecf20Sopenharmony_ci if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* When link is OK we have a device insertion. 2458c2ecf20Sopenharmony_ci * Request port soft reset to clear errors if they present. 2468c2ecf20Sopenharmony_ci * Inbound and outbound ackIDs will be 0 after reset. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci if (err_status & (RIO_PORT_N_ERR_STS_OUT_ES | 2498c2ecf20Sopenharmony_ci RIO_PORT_N_ERR_STS_INP_ES)) { 2508c2ecf20Sopenharmony_ci rio_read_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum), &rval); 2518c2ecf20Sopenharmony_ci rio_write_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum), 2528c2ecf20Sopenharmony_ci rval | RIO_PLM_SPx_IMP_SPEC_CTL_SOFT_RST); 2538c2ecf20Sopenharmony_ci udelay(10); 2548c2ecf20Sopenharmony_ci rio_write_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum), rval); 2558c2ecf20Sopenharmony_ci msleep(500); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic struct rio_switch_ops idtg3_switch_ops = { 2628c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2638c2ecf20Sopenharmony_ci .add_entry = idtg3_route_add_entry, 2648c2ecf20Sopenharmony_ci .get_entry = idtg3_route_get_entry, 2658c2ecf20Sopenharmony_ci .clr_table = idtg3_route_clr_table, 2668c2ecf20Sopenharmony_ci .em_init = idtg3_em_init, 2678c2ecf20Sopenharmony_ci .em_handle = idtg3_em_handler, 2688c2ecf20Sopenharmony_ci}; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int idtg3_probe(struct rio_dev *rdev, const struct rio_device_id *id) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci spin_lock(&rdev->rswitch->lock); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (rdev->rswitch->ops) { 2778c2ecf20Sopenharmony_ci spin_unlock(&rdev->rswitch->lock); 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci rdev->rswitch->ops = &idtg3_switch_ops; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (rdev->do_enum) { 2848c2ecf20Sopenharmony_ci /* Disable hierarchical routing support: Existing fabric 2858c2ecf20Sopenharmony_ci * enumeration/discovery process (see rio-scan.c) uses 8-bit 2868c2ecf20Sopenharmony_ci * flat destination ID routing only. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 0x5000 + RIO_BC_RT_CTL_CSR, 0); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci spin_unlock(&rdev->rswitch->lock); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void idtg3_remove(struct rio_dev *rdev) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 2998c2ecf20Sopenharmony_ci spin_lock(&rdev->rswitch->lock); 3008c2ecf20Sopenharmony_ci if (rdev->rswitch->ops == &idtg3_switch_ops) 3018c2ecf20Sopenharmony_ci rdev->rswitch->ops = NULL; 3028c2ecf20Sopenharmony_ci spin_unlock(&rdev->rswitch->lock); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* 3068c2ecf20Sopenharmony_ci * Gen3 switches repeat sending PW messages until a corresponding event flag 3078c2ecf20Sopenharmony_ci * is cleared. Use shutdown notification to disable generation of port-write 3088c2ecf20Sopenharmony_ci * messages if their destination node is shut down. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_cistatic void idtg3_shutdown(struct rio_dev *rdev) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci int i; 3138c2ecf20Sopenharmony_ci u32 rval; 3148c2ecf20Sopenharmony_ci u16 destid; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* Currently the enumerator node acts also as PW handler */ 3178c2ecf20Sopenharmony_ci if (!rdev->do_enum) 3188c2ecf20Sopenharmony_ci return; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci pr_debug("RIO: %s(%s)\n", __func__, rio_name(rdev)); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci rio_read_config_32(rdev, RIO_PW_ROUTE, &rval); 3238c2ecf20Sopenharmony_ci i = RIO_GET_PORT_NUM(rdev->swpinfo); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* Check port-write destination port */ 3268c2ecf20Sopenharmony_ci if (!((1 << i) & rval)) 3278c2ecf20Sopenharmony_ci return; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Disable sending port-write event notifications if PW destID 3308c2ecf20Sopenharmony_ci * matches to one of the enumerator node 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TGT_DEVID, &rval); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (rval & RIO_EM_PW_TGT_DEVID_DEV16) 3358c2ecf20Sopenharmony_ci destid = rval >> 16; 3368c2ecf20Sopenharmony_ci else 3378c2ecf20Sopenharmony_ci destid = ((rval & RIO_EM_PW_TGT_DEVID_D8) >> 16); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (rdev->net->hport->host_deviceid == destid) { 3408c2ecf20Sopenharmony_ci rio_write_config_32(rdev, 3418c2ecf20Sopenharmony_ci rdev->em_efptr + RIO_EM_PW_TX_CTRL, 0); 3428c2ecf20Sopenharmony_ci pr_debug("RIO: %s(%s) PW transmission disabled\n", 3438c2ecf20Sopenharmony_ci __func__, rio_name(rdev)); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic const struct rio_device_id idtg3_id_table[] = { 3488c2ecf20Sopenharmony_ci {RIO_DEVICE(RIO_DID_IDTRXS1632, RIO_VID_IDT)}, 3498c2ecf20Sopenharmony_ci {RIO_DEVICE(RIO_DID_IDTRXS2448, RIO_VID_IDT)}, 3508c2ecf20Sopenharmony_ci { 0, } /* terminate list */ 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic struct rio_driver idtg3_driver = { 3548c2ecf20Sopenharmony_ci .name = "idt_gen3", 3558c2ecf20Sopenharmony_ci .id_table = idtg3_id_table, 3568c2ecf20Sopenharmony_ci .probe = idtg3_probe, 3578c2ecf20Sopenharmony_ci .remove = idtg3_remove, 3588c2ecf20Sopenharmony_ci .shutdown = idtg3_shutdown, 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int __init idtg3_init(void) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci return rio_register_driver(&idtg3_driver); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic void __exit idtg3_exit(void) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci pr_debug("RIO: %s\n", __func__); 3698c2ecf20Sopenharmony_ci rio_unregister_driver(&idtg3_driver); 3708c2ecf20Sopenharmony_ci pr_debug("RIO: %s done\n", __func__); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cidevice_initcall(idtg3_init); 3748c2ecf20Sopenharmony_cimodule_exit(idtg3_exit); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IDT RXS Gen.3 Serial RapidIO switch family driver"); 3778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Integrated Device Technology, Inc."); 3788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 379