root/drivers/rapidio/switches/tsi57x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tsi57x_route_add_entry
  2. tsi57x_route_get_entry
  3. tsi57x_route_clr_table
  4. tsi57x_set_domain
  5. tsi57x_get_domain
  6. tsi57x_em_init
  7. tsi57x_em_handler
  8. tsi57x_probe
  9. tsi57x_remove
  10. tsi57x_init
  11. tsi57x_exit

   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 
  41 static int
  42 tsi57x_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 
  62 static int
  63 tsi57x_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 
  89 static int
  90 tsi57x_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 
 116 static int
 117 tsi57x_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, &regval);
 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 
 138 static int
 139 tsi57x_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, &regval);
 149 
 150         *sw_domain = (u8)(regval >> 24);
 151 
 152         return 0;
 153 }
 154 
 155 static int
 156 tsi57x_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), &regval);
 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                                 &regval);
 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), &regval);
 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), &regval);
 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                                 &regval);
 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 
 208 static int
 209 tsi57x_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                         &regval);
 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                         &regval);
 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                                         &regval);
 259                                 if (regval & RIO_PORT_N_MNT_RSP_RVAL)
 260                                         goto exit_es;
 261                         }
 262 
 263                         sendcount--;
 264                 }
 265         }
 266 
 267 exit_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), &regval);
 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 
 290 static 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 
 301 static 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 
 323 static 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 
 335 static 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 
 343 static struct rio_driver tsi57x_driver = {
 344         .name = "tsi57x",
 345         .id_table = tsi57x_id_table,
 346         .probe = tsi57x_probe,
 347         .remove = tsi57x_remove,
 348 };
 349 
 350 static int __init tsi57x_init(void)
 351 {
 352         return rio_register_driver(&tsi57x_driver);
 353 }
 354 
 355 static void __exit tsi57x_exit(void)
 356 {
 357         rio_unregister_driver(&tsi57x_driver);
 358 }
 359 
 360 device_initcall(tsi57x_init);
 361 module_exit(tsi57x_exit);
 362 
 363 MODULE_DESCRIPTION("IDT Tsi57x Serial RapidIO switch family driver");
 364 MODULE_AUTHOR("Integrated Device Technology, Inc.");
 365 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */