linux/drivers/staging/octeon/ethernet-spi.c
<<
>>
Prefs
   1/**********************************************************************
   2 * Author: Cavium Networks
   3 *
   4 * Contact: support@caviumnetworks.com
   5 * This file is part of the OCTEON SDK
   6 *
   7 * Copyright (c) 2003-2007 Cavium Networks
   8 *
   9 * This file is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License, Version 2, as
  11 * published by the Free Software Foundation.
  12 *
  13 * This file is distributed in the hope that it will be useful, but
  14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
  15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
  16 * NONINFRINGEMENT.  See the GNU General Public License for more
  17 * details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this file; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22 * or visit http://www.gnu.org/licenses/.
  23 *
  24 * This file may also be available under a different license from Cavium.
  25 * Contact Cavium Networks for more information
  26**********************************************************************/
  27#include <linux/kernel.h>
  28#include <linux/netdevice.h>
  29#include <linux/interrupt.h>
  30#include <net/dst.h>
  31
  32#include <asm/octeon/octeon.h>
  33
  34#include "ethernet-defines.h"
  35#include "octeon-ethernet.h"
  36#include "ethernet-util.h"
  37
  38#include <asm/octeon/cvmx-spi.h>
  39
  40#include <asm/octeon/cvmx-npi-defs.h>
  41#include <asm/octeon/cvmx-spxx-defs.h>
  42#include <asm/octeon/cvmx-stxx-defs.h>
  43
  44static int number_spi_ports;
  45static int need_retrain[2] = { 0, 0 };
  46
  47static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id)
  48{
  49        irqreturn_t return_status = IRQ_NONE;
  50        union cvmx_npi_rsl_int_blocks rsl_int_blocks;
  51
  52        /* Check and see if this interrupt was caused by the GMX block */
  53        rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
  54        if (rsl_int_blocks.s.spx1) {    /* 19 - SPX1_INT_REG & STX1_INT_REG */
  55
  56                union cvmx_spxx_int_reg spx_int_reg;
  57                union cvmx_stxx_int_reg stx_int_reg;
  58
  59                spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(1));
  60                cvmx_write_csr(CVMX_SPXX_INT_REG(1), spx_int_reg.u64);
  61                if (!need_retrain[1]) {
  62
  63                        spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(1));
  64                        if (spx_int_reg.s.spf)
  65                                pr_err("SPI1: SRX Spi4 interface down\n");
  66                        if (spx_int_reg.s.calerr)
  67                                pr_err("SPI1: SRX Spi4 Calendar table parity error\n");
  68                        if (spx_int_reg.s.syncerr)
  69                                pr_err("SPI1: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
  70                        if (spx_int_reg.s.diperr)
  71                                pr_err("SPI1: SRX Spi4 DIP4 error\n");
  72                        if (spx_int_reg.s.tpaovr)
  73                                pr_err("SPI1: SRX Selected port has hit TPA overflow\n");
  74                        if (spx_int_reg.s.rsverr)
  75                                pr_err("SPI1: SRX Spi4 reserved control word detected\n");
  76                        if (spx_int_reg.s.drwnng)
  77                                pr_err("SPI1: SRX Spi4 receive FIFO drowning/overflow\n");
  78                        if (spx_int_reg.s.clserr)
  79                                pr_err("SPI1: SRX Spi4 packet closed on non-16B alignment without EOP\n");
  80                        if (spx_int_reg.s.spiovr)
  81                                pr_err("SPI1: SRX Spi4 async FIFO overflow\n");
  82                        if (spx_int_reg.s.abnorm)
  83                                pr_err("SPI1: SRX Abnormal packet termination (ERR bit)\n");
  84                        if (spx_int_reg.s.prtnxa)
  85                                pr_err("SPI1: SRX Port out of range\n");
  86                }
  87
  88                stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(1));
  89                cvmx_write_csr(CVMX_STXX_INT_REG(1), stx_int_reg.u64);
  90                if (!need_retrain[1]) {
  91
  92                        stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1));
  93                        if (stx_int_reg.s.syncerr)
  94                                pr_err("SPI1: STX Interface encountered a fatal error\n");
  95                        if (stx_int_reg.s.frmerr)
  96                                pr_err("SPI1: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
  97                        if (stx_int_reg.s.unxfrm)
  98                                pr_err("SPI1: STX Unexpected framing sequence\n");
  99                        if (stx_int_reg.s.nosync)
 100                                pr_err("SPI1: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
 101                        if (stx_int_reg.s.diperr)
 102                                pr_err("SPI1: STX DIP2 error on the Spi4 Status channel\n");
 103                        if (stx_int_reg.s.datovr)
 104                                pr_err("SPI1: STX Spi4 FIFO overflow error\n");
 105                        if (stx_int_reg.s.ovrbst)
 106                                pr_err("SPI1: STX Transmit packet burst too big\n");
 107                        if (stx_int_reg.s.calpar1)
 108                                pr_err("SPI1: STX Calendar Table Parity Error Bank1\n");
 109                        if (stx_int_reg.s.calpar0)
 110                                pr_err("SPI1: STX Calendar Table Parity Error Bank0\n");
 111                }
 112
 113                cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0);
 114                cvmx_write_csr(CVMX_STXX_INT_MSK(1), 0);
 115                need_retrain[1] = 1;
 116                return_status = IRQ_HANDLED;
 117        }
 118
 119        if (rsl_int_blocks.s.spx0) {    /* 18 - SPX0_INT_REG & STX0_INT_REG */
 120                union cvmx_spxx_int_reg spx_int_reg;
 121                union cvmx_stxx_int_reg stx_int_reg;
 122
 123                spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(0));
 124                cvmx_write_csr(CVMX_SPXX_INT_REG(0), spx_int_reg.u64);
 125                if (!need_retrain[0]) {
 126
 127                        spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(0));
 128                        if (spx_int_reg.s.spf)
 129                                pr_err("SPI0: SRX Spi4 interface down\n");
 130                        if (spx_int_reg.s.calerr)
 131                                pr_err("SPI0: SRX Spi4 Calendar table parity error\n");
 132                        if (spx_int_reg.s.syncerr)
 133                                pr_err("SPI0: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n");
 134                        if (spx_int_reg.s.diperr)
 135                                pr_err("SPI0: SRX Spi4 DIP4 error\n");
 136                        if (spx_int_reg.s.tpaovr)
 137                                pr_err("SPI0: SRX Selected port has hit TPA overflow\n");
 138                        if (spx_int_reg.s.rsverr)
 139                                pr_err("SPI0: SRX Spi4 reserved control word detected\n");
 140                        if (spx_int_reg.s.drwnng)
 141                                pr_err("SPI0: SRX Spi4 receive FIFO drowning/overflow\n");
 142                        if (spx_int_reg.s.clserr)
 143                                pr_err("SPI0: SRX Spi4 packet closed on non-16B alignment without EOP\n");
 144                        if (spx_int_reg.s.spiovr)
 145                                pr_err("SPI0: SRX Spi4 async FIFO overflow\n");
 146                        if (spx_int_reg.s.abnorm)
 147                                pr_err("SPI0: SRX Abnormal packet termination (ERR bit)\n");
 148                        if (spx_int_reg.s.prtnxa)
 149                                pr_err("SPI0: SRX Port out of range\n");
 150                }
 151
 152                stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(0));
 153                cvmx_write_csr(CVMX_STXX_INT_REG(0), stx_int_reg.u64);
 154                if (!need_retrain[0]) {
 155
 156                        stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0));
 157                        if (stx_int_reg.s.syncerr)
 158                                pr_err("SPI0: STX Interface encountered a fatal error\n");
 159                        if (stx_int_reg.s.frmerr)
 160                                pr_err("SPI0: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n");
 161                        if (stx_int_reg.s.unxfrm)
 162                                pr_err("SPI0: STX Unexpected framing sequence\n");
 163                        if (stx_int_reg.s.nosync)
 164                                pr_err("SPI0: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n");
 165                        if (stx_int_reg.s.diperr)
 166                                pr_err("SPI0: STX DIP2 error on the Spi4 Status channel\n");
 167                        if (stx_int_reg.s.datovr)
 168                                pr_err("SPI0: STX Spi4 FIFO overflow error\n");
 169                        if (stx_int_reg.s.ovrbst)
 170                                pr_err("SPI0: STX Transmit packet burst too big\n");
 171                        if (stx_int_reg.s.calpar1)
 172                                pr_err("SPI0: STX Calendar Table Parity Error Bank1\n");
 173                        if (stx_int_reg.s.calpar0)
 174                                pr_err("SPI0: STX Calendar Table Parity Error Bank0\n");
 175                }
 176
 177                cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0);
 178                cvmx_write_csr(CVMX_STXX_INT_MSK(0), 0);
 179                need_retrain[0] = 1;
 180                return_status = IRQ_HANDLED;
 181        }
 182
 183        return return_status;
 184}
 185
 186static void cvm_oct_spi_enable_error_reporting(int interface)
 187{
 188        union cvmx_spxx_int_msk spxx_int_msk;
 189        union cvmx_stxx_int_msk stxx_int_msk;
 190
 191        spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
 192        spxx_int_msk.s.calerr = 1;
 193        spxx_int_msk.s.syncerr = 1;
 194        spxx_int_msk.s.diperr = 1;
 195        spxx_int_msk.s.tpaovr = 1;
 196        spxx_int_msk.s.rsverr = 1;
 197        spxx_int_msk.s.drwnng = 1;
 198        spxx_int_msk.s.clserr = 1;
 199        spxx_int_msk.s.spiovr = 1;
 200        spxx_int_msk.s.abnorm = 1;
 201        spxx_int_msk.s.prtnxa = 1;
 202        cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
 203
 204        stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
 205        stxx_int_msk.s.frmerr = 1;
 206        stxx_int_msk.s.unxfrm = 1;
 207        stxx_int_msk.s.nosync = 1;
 208        stxx_int_msk.s.diperr = 1;
 209        stxx_int_msk.s.datovr = 1;
 210        stxx_int_msk.s.ovrbst = 1;
 211        stxx_int_msk.s.calpar1 = 1;
 212        stxx_int_msk.s.calpar0 = 1;
 213        cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
 214}
 215
 216static void cvm_oct_spi_poll(struct net_device *dev)
 217{
 218        static int spi4000_port;
 219        struct octeon_ethernet *priv = netdev_priv(dev);
 220        int interface;
 221
 222        for (interface = 0; interface < 2; interface++) {
 223
 224                if ((priv->port == interface * 16) && need_retrain[interface]) {
 225
 226                        if (cvmx_spi_restart_interface
 227                            (interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {
 228                                need_retrain[interface] = 0;
 229                                cvm_oct_spi_enable_error_reporting(interface);
 230                        }
 231                }
 232
 233                /*
 234                 * The SPI4000 TWSI interface is very slow. In order
 235                 * not to bring the system to a crawl, we only poll a
 236                 * single port every second. This means negotiation
 237                 * speed changes take up to 10 seconds, but at least
 238                 * we don't waste absurd amounts of time waiting for
 239                 * TWSI.
 240                 */
 241                if (priv->port == spi4000_port) {
 242                        /*
 243                         * This function does nothing if it is called on an
 244                         * interface without a SPI4000.
 245                         */
 246                        cvmx_spi4000_check_speed(interface, priv->port);
 247                        /*
 248                         * Normal ordering increments. By decrementing
 249                         * we only match once per iteration.
 250                         */
 251                        spi4000_port--;
 252                        if (spi4000_port < 0)
 253                                spi4000_port = 10;
 254                }
 255        }
 256}
 257
 258int cvm_oct_spi_init(struct net_device *dev)
 259{
 260        int r;
 261        struct octeon_ethernet *priv = netdev_priv(dev);
 262
 263        if (number_spi_ports == 0) {
 264                r = request_irq(OCTEON_IRQ_RML, cvm_oct_spi_rml_interrupt,
 265                                IRQF_SHARED, "SPI", &number_spi_ports);
 266                if (r)
 267                        return r;
 268        }
 269        number_spi_ports++;
 270
 271        if ((priv->port == 0) || (priv->port == 16)) {
 272                cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));
 273                priv->poll = cvm_oct_spi_poll;
 274        }
 275        cvm_oct_common_init(dev);
 276        return 0;
 277}
 278
 279void cvm_oct_spi_uninit(struct net_device *dev)
 280{
 281        int interface;
 282
 283        cvm_oct_common_uninit(dev);
 284        number_spi_ports--;
 285        if (number_spi_ports == 0) {
 286                for (interface = 0; interface < 2; interface++) {
 287                        cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
 288                        cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
 289                }
 290                free_irq(OCTEON_IRQ_RML, &number_spi_ports);
 291        }
 292}
 293