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