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 "
  68                                       "parity error\n");
  69                        if (spx_int_reg.s.syncerr)
  70                                pr_err("SPI1: SRX Consecutive Spi4 DIP4 "
  71                                       "errors have exceeded "
  72                                       "SPX_ERR_CTL[ERRCNT]\n");
  73                        if (spx_int_reg.s.diperr)
  74                                pr_err("SPI1: SRX Spi4 DIP4 error\n");
  75                        if (spx_int_reg.s.tpaovr)
  76                                pr_err("SPI1: SRX Selected port has hit "
  77                                       "TPA overflow\n");
  78                        if (spx_int_reg.s.rsverr)
  79                                pr_err("SPI1: SRX Spi4 reserved control "
  80                                       "word detected\n");
  81                        if (spx_int_reg.s.drwnng)
  82                                pr_err("SPI1: SRX Spi4 receive FIFO "
  83                                       "drowning/overflow\n");
  84                        if (spx_int_reg.s.clserr)
  85                                pr_err("SPI1: SRX Spi4 packet closed on "
  86                                       "non-16B alignment without EOP\n");
  87                        if (spx_int_reg.s.spiovr)
  88                                pr_err("SPI1: SRX Spi4 async FIFO overflow\n");
  89                        if (spx_int_reg.s.abnorm)
  90                                pr_err("SPI1: SRX Abnormal packet "
  91                                       "termination (ERR bit)\n");
  92                        if (spx_int_reg.s.prtnxa)
  93                                pr_err("SPI1: SRX Port out of range\n");
  94                }
  95
  96                stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(1));
  97                cvmx_write_csr(CVMX_STXX_INT_REG(1), stx_int_reg.u64);
  98                if (!need_retrain[1]) {
  99
 100                        stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(1));
 101                        if (stx_int_reg.s.syncerr)
 102                                pr_err("SPI1: STX Interface encountered a "
 103                                       "fatal error\n");
 104                        if (stx_int_reg.s.frmerr)
 105                                pr_err("SPI1: STX FRMCNT has exceeded "
 106                                       "STX_DIP_CNT[MAXFRM]\n");
 107                        if (stx_int_reg.s.unxfrm)
 108                                pr_err("SPI1: STX Unexpected framing "
 109                                       "sequence\n");
 110                        if (stx_int_reg.s.nosync)
 111                                pr_err("SPI1: STX ERRCNT has exceeded "
 112                                       "STX_DIP_CNT[MAXDIP]\n");
 113                        if (stx_int_reg.s.diperr)
 114                                pr_err("SPI1: STX DIP2 error on the Spi4 "
 115                                       "Status channel\n");
 116                        if (stx_int_reg.s.datovr)
 117                                pr_err("SPI1: STX Spi4 FIFO overflow error\n");
 118                        if (stx_int_reg.s.ovrbst)
 119                                pr_err("SPI1: STX Transmit packet burst "
 120                                       "too big\n");
 121                        if (stx_int_reg.s.calpar1)
 122                                pr_err("SPI1: STX Calendar Table Parity "
 123                                       "Error Bank1\n");
 124                        if (stx_int_reg.s.calpar0)
 125                                pr_err("SPI1: STX Calendar Table Parity "
 126                                       "Error Bank0\n");
 127                }
 128
 129                cvmx_write_csr(CVMX_SPXX_INT_MSK(1), 0);
 130                cvmx_write_csr(CVMX_STXX_INT_MSK(1), 0);
 131                need_retrain[1] = 1;
 132                return_status = IRQ_HANDLED;
 133        }
 134
 135        if (rsl_int_blocks.s.spx0) {    /* 18 - SPX0_INT_REG & STX0_INT_REG */
 136                union cvmx_spxx_int_reg spx_int_reg;
 137                union cvmx_stxx_int_reg stx_int_reg;
 138
 139                spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(0));
 140                cvmx_write_csr(CVMX_SPXX_INT_REG(0), spx_int_reg.u64);
 141                if (!need_retrain[0]) {
 142
 143                        spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(0));
 144                        if (spx_int_reg.s.spf)
 145                                pr_err("SPI0: SRX Spi4 interface down\n");
 146                        if (spx_int_reg.s.calerr)
 147                                pr_err("SPI0: SRX Spi4 Calendar table "
 148                                       "parity error\n");
 149                        if (spx_int_reg.s.syncerr)
 150                                pr_err("SPI0: SRX Consecutive Spi4 DIP4 "
 151                                       "errors have exceeded "
 152                                       "SPX_ERR_CTL[ERRCNT]\n");
 153                        if (spx_int_reg.s.diperr)
 154                                pr_err("SPI0: SRX Spi4 DIP4 error\n");
 155                        if (spx_int_reg.s.tpaovr)
 156                                pr_err("SPI0: SRX Selected port has hit "
 157                                       "TPA overflow\n");
 158                        if (spx_int_reg.s.rsverr)
 159                                pr_err("SPI0: SRX Spi4 reserved control "
 160                                       "word detected\n");
 161                        if (spx_int_reg.s.drwnng)
 162                                pr_err("SPI0: SRX Spi4 receive FIFO "
 163                                       "drowning/overflow\n");
 164                        if (spx_int_reg.s.clserr)
 165                                pr_err("SPI0: SRX Spi4 packet closed on "
 166                                       "non-16B alignment without EOP\n");
 167                        if (spx_int_reg.s.spiovr)
 168                                pr_err("SPI0: SRX Spi4 async FIFO overflow\n");
 169                        if (spx_int_reg.s.abnorm)
 170                                pr_err("SPI0: SRX Abnormal packet "
 171                                       "termination (ERR bit)\n");
 172                        if (spx_int_reg.s.prtnxa)
 173                                pr_err("SPI0: SRX Port out of range\n");
 174                }
 175
 176                stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(0));
 177                cvmx_write_csr(CVMX_STXX_INT_REG(0), stx_int_reg.u64);
 178                if (!need_retrain[0]) {
 179
 180                        stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(0));
 181                        if (stx_int_reg.s.syncerr)
 182                                pr_err("SPI0: STX Interface encountered a "
 183                                       "fatal error\n");
 184                        if (stx_int_reg.s.frmerr)
 185                                pr_err("SPI0: STX FRMCNT has exceeded "
 186                                       "STX_DIP_CNT[MAXFRM]\n");
 187                        if (stx_int_reg.s.unxfrm)
 188                                pr_err("SPI0: STX Unexpected framing "
 189                                       "sequence\n");
 190                        if (stx_int_reg.s.nosync)
 191                                pr_err("SPI0: STX ERRCNT has exceeded "
 192                                       "STX_DIP_CNT[MAXDIP]\n");
 193                        if (stx_int_reg.s.diperr)
 194                                pr_err("SPI0: STX DIP2 error on the Spi4 "
 195                                       "Status channel\n");
 196                        if (stx_int_reg.s.datovr)
 197                                pr_err("SPI0: STX Spi4 FIFO overflow error\n");
 198                        if (stx_int_reg.s.ovrbst)
 199                                pr_err("SPI0: STX Transmit packet burst "
 200                                       "too big\n");
 201                        if (stx_int_reg.s.calpar1)
 202                                pr_err("SPI0: STX Calendar Table Parity "
 203                                       "Error Bank1\n");
 204                        if (stx_int_reg.s.calpar0)
 205                                pr_err("SPI0: STX Calendar Table Parity "
 206                                       "Error Bank0\n");
 207                }
 208
 209                cvmx_write_csr(CVMX_SPXX_INT_MSK(0), 0);
 210                cvmx_write_csr(CVMX_STXX_INT_MSK(0), 0);
 211                need_retrain[0] = 1;
 212                return_status = IRQ_HANDLED;
 213        }
 214
 215        return return_status;
 216}
 217
 218static void cvm_oct_spi_enable_error_reporting(int interface)
 219{
 220        union cvmx_spxx_int_msk spxx_int_msk;
 221        union cvmx_stxx_int_msk stxx_int_msk;
 222
 223        spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
 224        spxx_int_msk.s.calerr = 1;
 225        spxx_int_msk.s.syncerr = 1;
 226        spxx_int_msk.s.diperr = 1;
 227        spxx_int_msk.s.tpaovr = 1;
 228        spxx_int_msk.s.rsverr = 1;
 229        spxx_int_msk.s.drwnng = 1;
 230        spxx_int_msk.s.clserr = 1;
 231        spxx_int_msk.s.spiovr = 1;
 232        spxx_int_msk.s.abnorm = 1;
 233        spxx_int_msk.s.prtnxa = 1;
 234        cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
 235
 236        stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
 237        stxx_int_msk.s.frmerr = 1;
 238        stxx_int_msk.s.unxfrm = 1;
 239        stxx_int_msk.s.nosync = 1;
 240        stxx_int_msk.s.diperr = 1;
 241        stxx_int_msk.s.datovr = 1;
 242        stxx_int_msk.s.ovrbst = 1;
 243        stxx_int_msk.s.calpar1 = 1;
 244        stxx_int_msk.s.calpar0 = 1;
 245        cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
 246}
 247
 248static void cvm_oct_spi_poll(struct net_device *dev)
 249{
 250        static int spi4000_port;
 251        struct octeon_ethernet *priv = netdev_priv(dev);
 252        int interface;
 253
 254        for (interface = 0; interface < 2; interface++) {
 255
 256                if ((priv->port == interface * 16) && need_retrain[interface]) {
 257
 258                        if (cvmx_spi_restart_interface
 259                            (interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {
 260                                need_retrain[interface] = 0;
 261                                cvm_oct_spi_enable_error_reporting(interface);
 262                        }
 263                }
 264
 265                /*
 266                 * The SPI4000 TWSI interface is very slow. In order
 267                 * not to bring the system to a crawl, we only poll a
 268                 * single port every second. This means negotiation
 269                 * speed changes take up to 10 seconds, but at least
 270                 * we don't waste absurd amounts of time waiting for
 271                 * TWSI.
 272                 */
 273                if (priv->port == spi4000_port) {
 274                        /*
 275                         * This function does nothing if it is called on an
 276                         * interface without a SPI4000.
 277                         */
 278                        cvmx_spi4000_check_speed(interface, priv->port);
 279                        /*
 280                         * Normal ordering increments. By decrementing
 281                         * we only match once per iteration.
 282                         */
 283                        spi4000_port--;
 284                        if (spi4000_port < 0)
 285                                spi4000_port = 10;
 286                }
 287        }
 288}
 289
 290int cvm_oct_spi_init(struct net_device *dev)
 291{
 292        int r;
 293        struct octeon_ethernet *priv = netdev_priv(dev);
 294
 295        if (number_spi_ports == 0) {
 296                r = request_irq(OCTEON_IRQ_RML, cvm_oct_spi_rml_interrupt,
 297                                IRQF_SHARED, "SPI", &number_spi_ports);
 298                if (r)
 299                        return r;
 300        }
 301        number_spi_ports++;
 302
 303        if ((priv->port == 0) || (priv->port == 16)) {
 304                cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));
 305                priv->poll = cvm_oct_spi_poll;
 306        }
 307        cvm_oct_common_init(dev);
 308        return 0;
 309}
 310
 311void cvm_oct_spi_uninit(struct net_device *dev)
 312{
 313        int interface;
 314
 315        cvm_oct_common_uninit(dev);
 316        number_spi_ports--;
 317        if (number_spi_ports == 0) {
 318                for (interface = 0; interface < 2; interface++) {
 319                        cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
 320                        cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
 321                }
 322                free_irq(OCTEON_IRQ_RML, &number_spi_ports);
 323        }
 324}
 325