1 /* 2 * IDT CPS RapidIO switches support 3 * 4 * Copyright 2009-2010 Integrated Device Technology, Inc. 5 * Alexandre Bounine <alexandre.bounine@idt.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or (at your 10 * option) any later version. 11 */ 12 13 #include <linux/rio.h> 14 #include <linux/rio_drv.h> 15 #include <linux/rio_ids.h> 16 #include <linux/module.h> 17 #include "../rio.h" 18 19 #define CPS_DEFAULT_ROUTE 0xde 20 #define CPS_NO_ROUTE 0xdf 21 22 #define IDTCPS_RIO_DOMAIN 0xf20020 23 24 static int 25 idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 26 u16 table, u16 route_destid, u8 route_port) 27 { 28 u32 result; 29 30 if (route_port == RIO_INVALID_ROUTE) 31 route_port = CPS_DEFAULT_ROUTE; 32 33 if (table == RIO_GLOBAL_TABLE) { 34 rio_mport_write_config_32(mport, destid, hopcount, 35 RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); 36 37 rio_mport_read_config_32(mport, destid, hopcount, 38 RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); 39 40 result = (0xffffff00 & result) | (u32)route_port; 41 rio_mport_write_config_32(mport, destid, hopcount, 42 RIO_STD_RTE_CONF_PORT_SEL_CSR, result); 43 } 44 45 return 0; 46 } 47 48 static int 49 idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 50 u16 table, u16 route_destid, u8 *route_port) 51 { 52 u32 result; 53 54 if (table == RIO_GLOBAL_TABLE) { 55 rio_mport_write_config_32(mport, destid, hopcount, 56 RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); 57 58 rio_mport_read_config_32(mport, destid, hopcount, 59 RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); 60 61 if (CPS_DEFAULT_ROUTE == (u8)result || 62 CPS_NO_ROUTE == (u8)result) 63 *route_port = RIO_INVALID_ROUTE; 64 else 65 *route_port = (u8)result; 66 } 67 68 return 0; 69 } 70 71 static int 72 idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 73 u16 table) 74 { 75 u32 i; 76 77 if (table == RIO_GLOBAL_TABLE) { 78 for (i = 0x80000000; i <= 0x800000ff;) { 79 rio_mport_write_config_32(mport, destid, hopcount, 80 RIO_STD_RTE_CONF_DESTID_SEL_CSR, i); 81 rio_mport_write_config_32(mport, destid, hopcount, 82 RIO_STD_RTE_CONF_PORT_SEL_CSR, 83 (CPS_DEFAULT_ROUTE << 24) | 84 (CPS_DEFAULT_ROUTE << 16) | 85 (CPS_DEFAULT_ROUTE << 8) | CPS_DEFAULT_ROUTE); 86 i += 4; 87 } 88 } 89 90 return 0; 91 } 92 93 static int 94 idtcps_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, 95 u8 sw_domain) 96 { 97 /* 98 * Switch domain configuration operates only at global level 99 */ 100 rio_mport_write_config_32(mport, destid, hopcount, 101 IDTCPS_RIO_DOMAIN, (u32)sw_domain); 102 return 0; 103 } 104 105 static int 106 idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, 107 u8 *sw_domain) 108 { 109 u32 regval; 110 111 /* 112 * Switch domain configuration operates only at global level 113 */ 114 rio_mport_read_config_32(mport, destid, hopcount, 115 IDTCPS_RIO_DOMAIN, ®val); 116 117 *sw_domain = (u8)(regval & 0xff); 118 119 return 0; 120 } 121 122 static struct rio_switch_ops idtcps_switch_ops = { 123 .owner = THIS_MODULE, 124 .add_entry = idtcps_route_add_entry, 125 .get_entry = idtcps_route_get_entry, 126 .clr_table = idtcps_route_clr_table, 127 .set_domain = idtcps_set_domain, 128 .get_domain = idtcps_get_domain, 129 .em_init = NULL, 130 .em_handle = NULL, 131 }; 132 133 static int idtcps_probe(struct rio_dev *rdev, const struct rio_device_id *id) 134 { 135 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 136 137 spin_lock(&rdev->rswitch->lock); 138 139 if (rdev->rswitch->ops) { 140 spin_unlock(&rdev->rswitch->lock); 141 return -EINVAL; 142 } 143 144 rdev->rswitch->ops = &idtcps_switch_ops; 145 146 if (rdev->do_enum) { 147 /* set TVAL = ~50us */ 148 rio_write_config_32(rdev, 149 rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); 150 /* Ensure that default routing is disabled on startup */ 151 rio_write_config_32(rdev, 152 RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE); 153 } 154 155 spin_unlock(&rdev->rswitch->lock); 156 return 0; 157 } 158 159 static void idtcps_remove(struct rio_dev *rdev) 160 { 161 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 162 spin_lock(&rdev->rswitch->lock); 163 if (rdev->rswitch->ops != &idtcps_switch_ops) { 164 spin_unlock(&rdev->rswitch->lock); 165 return; 166 } 167 rdev->rswitch->ops = NULL; 168 spin_unlock(&rdev->rswitch->lock); 169 } 170 171 static struct rio_device_id idtcps_id_table[] = { 172 {RIO_DEVICE(RIO_DID_IDTCPS6Q, RIO_VID_IDT)}, 173 {RIO_DEVICE(RIO_DID_IDTCPS8, RIO_VID_IDT)}, 174 {RIO_DEVICE(RIO_DID_IDTCPS10Q, RIO_VID_IDT)}, 175 {RIO_DEVICE(RIO_DID_IDTCPS12, RIO_VID_IDT)}, 176 {RIO_DEVICE(RIO_DID_IDTCPS16, RIO_VID_IDT)}, 177 {RIO_DEVICE(RIO_DID_IDT70K200, RIO_VID_IDT)}, 178 { 0, } /* terminate list */ 179 }; 180 181 static struct rio_driver idtcps_driver = { 182 .name = "idtcps", 183 .id_table = idtcps_id_table, 184 .probe = idtcps_probe, 185 .remove = idtcps_remove, 186 }; 187 188 static int __init idtcps_init(void) 189 { 190 return rio_register_driver(&idtcps_driver); 191 } 192 193 static void __exit idtcps_exit(void) 194 { 195 rio_unregister_driver(&idtcps_driver); 196 } 197 198 device_initcall(idtcps_init); 199 module_exit(idtcps_exit); 200 201 MODULE_DESCRIPTION("IDT CPS Gen.1 Serial RapidIO switch family driver"); 202 MODULE_AUTHOR("Integrated Device Technology, Inc."); 203 MODULE_LICENSE("GPL"); 204