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