linux/drivers/net/ixp2000/enp2611.c
<<
>>
Prefs
   1/*
   2 * IXP2400 MSF network device driver for the Radisys ENP2611
   3 * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
   4 * Dedicated to Marija Kulikova.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/kernel.h>
  14#include <linux/netdevice.h>
  15#include <linux/etherdevice.h>
  16#include <linux/init.h>
  17#include <linux/moduleparam.h>
  18#include <asm/hardware/uengine.h>
  19#include <asm/mach-types.h>
  20#include <asm/io.h>
  21#include "ixpdev.h"
  22#include "caleb.h"
  23#include "ixp2400-msf.h"
  24#include "pm3386.h"
  25
  26/***********************************************************************
  27 * The Radisys ENP2611 is a PCI form factor board with three SFP GBIC
  28 * slots, connected via two PMC/Sierra 3386s and an SPI-3 bridge FPGA
  29 * to the IXP2400.
  30 *
  31 *                +-------------+
  32 * SFP GBIC #0 ---+             |       +---------+
  33 *                |  PM3386 #0  +-------+         |
  34 * SFP GBIC #1 ---+             |       | "Caleb" |         +---------+
  35 *                +-------------+       |         |         |         |
  36 *                                      | SPI-3   +---------+ IXP2400 |
  37 *                +-------------+       | bridge  |         |         |
  38 * SFP GBIC #2 ---+             |       | FPGA    |         +---------+
  39 *                |  PM3386 #1  +-------+         |
  40 *                |             |       +---------+
  41 *                +-------------+
  42 *              ^                   ^                  ^
  43 *              | 1.25Gbaud         | 104MHz           | 104MHz
  44 *              | SERDES ea.        | SPI-3 ea.        | SPI-3
  45 *
  46 ***********************************************************************/
  47static struct ixp2400_msf_parameters enp2611_msf_parameters =
  48{
  49        .rx_mode =              IXP2400_RX_MODE_UTOPIA_POS |
  50                                IXP2400_RX_MODE_1x32 |
  51                                IXP2400_RX_MODE_MPHY |
  52                                IXP2400_RX_MODE_MPHY_32 |
  53                                IXP2400_RX_MODE_MPHY_POLLED_STATUS |
  54                                IXP2400_RX_MODE_MPHY_LEVEL3 |
  55                                IXP2400_RX_MODE_RBUF_SIZE_64,
  56
  57        .rxclk01_multiplier =   IXP2400_PLL_MULTIPLIER_16,
  58
  59        .rx_poll_ports =        3,
  60
  61        .rx_channel_mode = {
  62                IXP2400_PORT_RX_MODE_MASTER |
  63                IXP2400_PORT_RX_MODE_POS_PHY |
  64                IXP2400_PORT_RX_MODE_POS_PHY_L3 |
  65                IXP2400_PORT_RX_MODE_ODD_PARITY |
  66                IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
  67
  68                IXP2400_PORT_RX_MODE_MASTER |
  69                IXP2400_PORT_RX_MODE_POS_PHY |
  70                IXP2400_PORT_RX_MODE_POS_PHY_L3 |
  71                IXP2400_PORT_RX_MODE_ODD_PARITY |
  72                IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
  73
  74                IXP2400_PORT_RX_MODE_MASTER |
  75                IXP2400_PORT_RX_MODE_POS_PHY |
  76                IXP2400_PORT_RX_MODE_POS_PHY_L3 |
  77                IXP2400_PORT_RX_MODE_ODD_PARITY |
  78                IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
  79
  80                IXP2400_PORT_RX_MODE_MASTER |
  81                IXP2400_PORT_RX_MODE_POS_PHY |
  82                IXP2400_PORT_RX_MODE_POS_PHY_L3 |
  83                IXP2400_PORT_RX_MODE_ODD_PARITY |
  84                IXP2400_PORT_RX_MODE_2_CYCLE_DECODE
  85        },
  86
  87        .tx_mode =              IXP2400_TX_MODE_UTOPIA_POS |
  88                                IXP2400_TX_MODE_1x32 |
  89                                IXP2400_TX_MODE_MPHY |
  90                                IXP2400_TX_MODE_MPHY_32 |
  91                                IXP2400_TX_MODE_MPHY_POLLED_STATUS |
  92                                IXP2400_TX_MODE_MPHY_LEVEL3 |
  93                                IXP2400_TX_MODE_TBUF_SIZE_64,
  94
  95        .txclk01_multiplier =   IXP2400_PLL_MULTIPLIER_16,
  96
  97        .tx_poll_ports =        3,
  98
  99        .tx_channel_mode = {
 100                IXP2400_PORT_TX_MODE_MASTER |
 101                IXP2400_PORT_TX_MODE_POS_PHY |
 102                IXP2400_PORT_TX_MODE_ODD_PARITY |
 103                IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
 104
 105                IXP2400_PORT_TX_MODE_MASTER |
 106                IXP2400_PORT_TX_MODE_POS_PHY |
 107                IXP2400_PORT_TX_MODE_ODD_PARITY |
 108                IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
 109
 110                IXP2400_PORT_TX_MODE_MASTER |
 111                IXP2400_PORT_TX_MODE_POS_PHY |
 112                IXP2400_PORT_TX_MODE_ODD_PARITY |
 113                IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
 114
 115                IXP2400_PORT_TX_MODE_MASTER |
 116                IXP2400_PORT_TX_MODE_POS_PHY |
 117                IXP2400_PORT_TX_MODE_ODD_PARITY |
 118                IXP2400_PORT_TX_MODE_2_CYCLE_DECODE
 119        }
 120};
 121
 122static struct net_device *nds[3];
 123static struct timer_list link_check_timer;
 124
 125/* @@@ Poll the SFP moddef0 line too.  */
 126/* @@@ Try to use the pm3386 DOOL interrupt as well.  */
 127static void enp2611_check_link_status(unsigned long __dummy)
 128{
 129        int i;
 130
 131        for (i = 0; i < 3; i++) {
 132                struct net_device *dev;
 133                int status;
 134
 135                dev = nds[i];
 136                if (dev == NULL)
 137                        continue;
 138
 139                status = pm3386_is_link_up(i);
 140                if (status && !netif_carrier_ok(dev)) {
 141                        /* @@@ Should report autonegotiation status.  */
 142                        printk(KERN_INFO "%s: NIC Link is Up\n", dev->name);
 143
 144                        pm3386_enable_tx(i);
 145                        caleb_enable_tx(i);
 146                        netif_carrier_on(dev);
 147                } else if (!status && netif_carrier_ok(dev)) {
 148                        printk(KERN_INFO "%s: NIC Link is Down\n", dev->name);
 149
 150                        netif_carrier_off(dev);
 151                        caleb_disable_tx(i);
 152                        pm3386_disable_tx(i);
 153                }
 154        }
 155
 156        link_check_timer.expires = jiffies + HZ / 10;
 157        add_timer(&link_check_timer);
 158}
 159
 160static void enp2611_set_port_admin_status(int port, int up)
 161{
 162        if (up) {
 163                caleb_enable_rx(port);
 164
 165                pm3386_set_carrier(port, 1);
 166                pm3386_enable_rx(port);
 167        } else {
 168                caleb_disable_tx(port);
 169                pm3386_disable_tx(port);
 170                /* @@@ Flush out pending packets.  */
 171                pm3386_set_carrier(port, 0);
 172
 173                pm3386_disable_rx(port);
 174                caleb_disable_rx(port);
 175        }
 176}
 177
 178static int __init enp2611_init_module(void)
 179{ 
 180        int ports;
 181        int i;
 182
 183        if (!machine_is_enp2611())
 184                return -ENODEV;
 185
 186        caleb_reset();
 187        pm3386_reset();
 188
 189        ports = pm3386_port_count();
 190        for (i = 0; i < ports; i++) {
 191                nds[i] = ixpdev_alloc(i, sizeof(struct ixpdev_priv));
 192                if (nds[i] == NULL) {
 193                        while (--i >= 0)
 194                                free_netdev(nds[i]);
 195                        return -ENOMEM;
 196                }
 197
 198                pm3386_init_port(i);
 199                pm3386_get_mac(i, nds[i]->dev_addr);
 200        }
 201
 202        ixp2400_msf_init(&enp2611_msf_parameters);
 203
 204        if (ixpdev_init(ports, nds, enp2611_set_port_admin_status)) {
 205                for (i = 0; i < ports; i++)
 206                        if (nds[i])
 207                                free_netdev(nds[i]);
 208                return -EINVAL;
 209        }
 210
 211        init_timer(&link_check_timer);
 212        link_check_timer.function = enp2611_check_link_status;
 213        link_check_timer.expires = jiffies;
 214        add_timer(&link_check_timer);
 215
 216        return 0;
 217}
 218
 219static void __exit enp2611_cleanup_module(void)
 220{
 221        int i;
 222
 223        del_timer_sync(&link_check_timer);
 224
 225        ixpdev_deinit();
 226        for (i = 0; i < 3; i++)
 227                free_netdev(nds[i]);
 228}
 229
 230module_init(enp2611_init_module);
 231module_exit(enp2611_cleanup_module);
 232MODULE_LICENSE("GPL");
 233