ath9k: allow run-time change of the chanbw debugfs file
[openwrt.git] / target / linux / adm5120 / files / drivers / net / adm5120sw.c
index c8c3f1d..a926954 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  ADM5120 built-in ethernet switch driver
  *
 /*
  *  ADM5120 built-in ethernet switch driver
  *
- *  Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
  *
  *  This code was based on a driver for Linux 2.6.xx by Jeroen Vreeken.
  *    Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
  *
  *  This code was based on a driver for Linux 2.6.xx by Jeroen Vreeken.
  *    Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#include <linux/io.h>
-#include <linux/irq.h>
-
 #include <asm/mipsregs.h>
 
 #include <asm/mipsregs.h>
 
-#include <adm5120_info.h>
-#include <adm5120_defs.h>
-#include <adm5120_irq.h>
-#include <adm5120_switch.h>
+#include <asm/mach-adm5120/adm5120_info.h>
+#include <asm/mach-adm5120/adm5120_defs.h>
+#include <asm/mach-adm5120/adm5120_switch.h>
 
 #include "adm5120sw.h"
 
 #define DRV_NAME       "adm5120-switch"
 #define DRV_DESC       "ADM5120 built-in ethernet switch driver"
 
 #include "adm5120sw.h"
 
 #define DRV_NAME       "adm5120-switch"
 #define DRV_DESC       "ADM5120 built-in ethernet switch driver"
-#define DRV_VERSION    "0.1.0"
+#define DRV_VERSION    "0.1.1"
 
 #define CONFIG_ADM5120_SWITCH_NAPI     1
 #undef CONFIG_ADM5120_SWITCH_DEBUG
 
 #define CONFIG_ADM5120_SWITCH_NAPI     1
 #undef CONFIG_ADM5120_SWITCH_DEBUG
@@ -66,7 +64,7 @@
 
 #define TX_RING_SIZE   32
 #define TX_QUEUE_LEN   28      /* Limit ring entries actually used. */
 
 #define TX_RING_SIZE   32
 #define TX_QUEUE_LEN   28      /* Limit ring entries actually used. */
-#define TX_TIMEOUT     HZ*400
+#define TX_TIMEOUT     (HZ * 400)
 
 #define RX_DESCS_SIZE  (RX_RING_SIZE * sizeof(struct dma_desc *))
 #define RX_SKBS_SIZE   (RX_RING_SIZE * sizeof(struct sk_buff *))
 
 #define RX_DESCS_SIZE  (RX_RING_SIZE * sizeof(struct dma_desc *))
 #define RX_SKBS_SIZE   (RX_RING_SIZE * sizeof(struct sk_buff *))
 /* ------------------------------------------------------------------------ */
 
 struct adm5120_if_priv {
 /* ------------------------------------------------------------------------ */
 
 struct adm5120_if_priv {
+       struct net_device *dev;
+
        unsigned int    vlan_no;
        unsigned int    port_mask;
        unsigned int    vlan_no;
        unsigned int    port_mask;
+
+#ifdef CONFIG_ADM5120_SWITCH_NAPI
+       struct napi_struct napi;
+#endif
 };
 
 struct dma_desc {
 };
 
 struct dma_desc {
@@ -228,7 +232,7 @@ static void sw_dump_desc(char *label, struct dma_desc *desc, int tx)
        t = desc->buf2;
        SW_DBG("    buf2 %08X addr=%08X%s\n", desc->buf2,
                t & DESC_ADDR_MASK,
        t = desc->buf2;
        SW_DBG("    buf2 %08X addr=%08X%s\n", desc->buf2,
                t & DESC_ADDR_MASK,
-               (t & DESC_BUF2_EN) ? " EN" : "" );
+               (t & DESC_BUF2_EN) ? " EN" : "");
 
        t = desc->misc;
        if (tx)
 
        t = desc->misc;
        if (tx)
@@ -333,7 +337,6 @@ static void sw_dump_regs(void)
        SW_DBG("rlda: %08X\n", t);
 }
 
        SW_DBG("rlda: %08X\n", t);
 }
 
-
 /* ------------------------------------------------------------------------ */
 
 static inline void adm5120_rx_dma_update(struct dma_desc *desc,
 /* ------------------------------------------------------------------------ */
 
 static inline void adm5120_rx_dma_update(struct dma_desc *desc,
@@ -430,7 +433,7 @@ static int adm5120_switch_rx(int limit)
                                dma_cache_wback_inv((unsigned long)skb->data,
                                        skb->len);
 
                                dma_cache_wback_inv((unsigned long)skb->data,
                                        skb->len);
 
-#ifdef CONFIG_ADM5120_SWITCH_USE_NAPI
+#ifdef CONFIG_ADM5120_SWITCH_NAPI
                                netif_receive_skb(skb);
 #else
                                netif_rx(skb);
                                netif_receive_skb(skb);
 #else
                                netif_rx(skb);
@@ -495,9 +498,11 @@ static void adm5120_switch_tx(void)
 }
 
 #ifdef CONFIG_ADM5120_SWITCH_NAPI
 }
 
 #ifdef CONFIG_ADM5120_SWITCH_NAPI
-static int adm5120_if_poll(struct net_device *dev, int *budget)
+static int adm5120_if_poll(struct napi_struct *napi, int limit)
 {
 {
-       int limit = min(dev->quota, *budget);
+       struct adm5120_if_priv *priv = container_of(napi,
+                               struct adm5120_if_priv, napi);
+       struct net_device *dev = priv->dev;
        int done;
        u32 status;
 
        int done;
        u32 status;
 
@@ -509,13 +514,10 @@ static int adm5120_if_poll(struct net_device *dev, int *budget)
        SW_DBG("%s: processing RX ring\n", dev->name);
        done = adm5120_switch_rx(limit);
 
        SW_DBG("%s: processing RX ring\n", dev->name);
        done = adm5120_switch_rx(limit);
 
-       *budget -= done;
-       dev->quota -= done;
-
        status = sw_int_status() & SWITCH_INTS_POLL;
        if ((done < limit) && (!status)) {
                SW_DBG("disable polling mode for %s\n", dev->name);
        status = sw_int_status() & SWITCH_INTS_POLL;
        if ((done < limit) && (!status)) {
                SW_DBG("disable polling mode for %s\n", dev->name);
-               netif_rx_complete(dev);
+               napi_complete(napi);
                sw_int_unmask(SWITCH_INTS_POLL);
                return 0;
        }
                sw_int_unmask(SWITCH_INTS_POLL);
                return 0;
        }
@@ -524,7 +526,7 @@ static int adm5120_if_poll(struct net_device *dev, int *budget)
                        dev->name, done, status);
        return 1;
 }
                        dev->name, done, status);
        return 1;
 }
-#endif /* CONFIG_ADM5120_SWITCH_USE_NAPI */
+#endif /* CONFIG_ADM5120_SWITCH_NAPI */
 
 
 static irqreturn_t adm5120_switch_irq(int irq, void *dev_id)
 
 
 static irqreturn_t adm5120_switch_irq(int irq, void *dev_id)
@@ -541,21 +543,21 @@ static irqreturn_t adm5120_switch_irq(int irq, void *dev_id)
 
        if (status & SWITCH_INTS_POLL) {
                struct net_device *dev = dev_id;
 
        if (status & SWITCH_INTS_POLL) {
                struct net_device *dev = dev_id;
+               struct adm5120_if_priv *priv = netdev_priv(dev);
+
                sw_dump_intr_mask("poll ints", status);
                SW_DBG("enable polling mode for %s\n", dev->name);
                sw_int_mask(SWITCH_INTS_POLL);
                sw_dump_intr_mask("poll ints", status);
                SW_DBG("enable polling mode for %s\n", dev->name);
                sw_int_mask(SWITCH_INTS_POLL);
-               netif_rx_schedule(dev);
+               napi_schedule(&priv->napi);
        }
 #else
        sw_int_ack(status);
 
        }
 #else
        sw_int_ack(status);
 
-       if (status & (SWITCH_INT_RLD | SWITCH_INT_LDF)) {
+       if (status & (SWITCH_INT_RLD | SWITCH_INT_LDF))
                adm5120_switch_rx(RX_RING_SIZE);
                adm5120_switch_rx(RX_RING_SIZE);
-       }
 
 
-       if (status & SWITCH_INT_SLD) {
+       if (status & SWITCH_INT_SLD)
                adm5120_switch_tx();
                adm5120_switch_tx();
-       }
 #endif
 
        return IRQ_HANDLED;
 #endif
 
        return IRQ_HANDLED;
@@ -585,7 +587,7 @@ static void adm5120_switch_tx_ring_reset(struct dma_desc *desc,
 {
        memset(desc, 0, num * sizeof(*desc));
        desc[num-1].buf1 |= DESC_EOR;
 {
        memset(desc, 0, num * sizeof(*desc));
        desc[num-1].buf1 |= DESC_EOR;
-       memset(skbl, 0, sizeof(struct skb*)*num);
+       memset(skbl, 0, sizeof(struct skb *) * num);
 
        cur_txl = 0;
        dirty_txl = 0;
 
        cur_txl = 0;
        dirty_txl = 0;
@@ -604,7 +606,7 @@ static void adm5120_switch_rx_ring_reset(struct dma_desc *desc,
                        break;
                }
                skb_reserve(skbl[i], SKB_RESERVE_LEN);
                        break;
                }
                skb_reserve(skbl[i], SKB_RESERVE_LEN);
-               adm5120_rx_dma_update(&desc[i], skbl[i], (num-1==i));
+               adm5120_rx_dma_update(&desc[i], skbl[i], (num - 1 == i));
        }
 
        cur_rxl = 0;
        }
 
        cur_rxl = 0;
@@ -717,7 +719,8 @@ static void adm5120_write_mac(struct net_device *dev)
 
        sw_write_reg(SWITCH_REG_MAC_WT0, t);
 
 
        sw_write_reg(SWITCH_REG_MAC_WT0, t);
 
-       while (!(sw_read_reg(SWITCH_REG_MAC_WT0) & MAC_WT0_MWD));
+       while (!(sw_read_reg(SWITCH_REG_MAC_WT0) & MAC_WT0_MWD))
+               ;
 }
 
 static void adm5120_set_vlan(char *matrix)
 }
 
 static void adm5120_set_vlan(char *matrix)
@@ -731,9 +734,10 @@ static void adm5120_set_vlan(char *matrix)
        sw_write_reg(SWITCH_REG_VLAN_G2, val);
 
        /* Now set/update the port vs. device lookup table */
        sw_write_reg(SWITCH_REG_VLAN_G2, val);
 
        /* Now set/update the port vs. device lookup table */
-       for (port=0; port<SWITCH_NUM_PORTS; port++) {
-               for (vlan_port=0; vlan_port<SWITCH_NUM_PORTS && !(matrix[vlan_port] & (0x00000001 << port)); vlan_port++);
-               if (vlan_port <SWITCH_NUM_PORTS)
+       for (port = 0; port < SWITCH_NUM_PORTS; port++) {
+               for (vlan_port = 0; vlan_port < SWITCH_NUM_PORTS && !(matrix[vlan_port] & (0x00000001 << port)); vlan_port++)
+                       ;
+               if (vlan_port < SWITCH_NUM_PORTS)
                        adm5120_port[port] = adm5120_devs[vlan_port];
                else
                        adm5120_port[port] = NULL;
                        adm5120_port[port] = adm5120_devs[vlan_port];
                else
                        adm5120_port[port] = NULL;
@@ -779,14 +783,33 @@ static void adm5120_switch_set_vlan_ports(unsigned int vlan, u32 ports)
 
 /* ------------------------------------------------------------------------ */
 
 
 /* ------------------------------------------------------------------------ */
 
+#ifdef CONFIG_ADM5120_SWITCH_NAPI
+static inline void adm5120_if_napi_enable(struct net_device *dev)
+{
+       struct adm5120_if_priv *priv = netdev_priv(dev);
+       napi_enable(&priv->napi);
+}
+
+static inline void adm5120_if_napi_disable(struct net_device *dev)
+{
+       struct adm5120_if_priv *priv = netdev_priv(dev);
+       napi_disable(&priv->napi);
+}
+#else
+static inline void adm5120_if_napi_enable(struct net_device *dev) {}
+static inline void adm5120_if_napi_disable(struct net_device *dev) {}
+#endif /* CONFIG_ADM5120_SWITCH_NAPI */
+
 static int adm5120_if_open(struct net_device *dev)
 {
        u32 t;
        int err;
        int i;
 
 static int adm5120_if_open(struct net_device *dev)
 {
        u32 t;
        int err;
        int i;
 
-       err = request_irq(dev->irq, adm5120_switch_irq,
-               (IRQF_SHARED | IRQF_DISABLED), dev->name, dev);
+       adm5120_if_napi_enable(dev);
+
+       err = request_irq(dev->irq, adm5120_switch_irq, IRQF_SHARED,
+                         dev->name, dev);
        if (err) {
                SW_ERR("unable to get irq for %s\n", dev->name);
                goto err;
        if (err) {
                SW_ERR("unable to get irq for %s\n", dev->name);
                goto err;
@@ -809,6 +832,7 @@ static int adm5120_if_open(struct net_device *dev)
        return 0;
 
 err:
        return 0;
 
 err:
+       adm5120_if_napi_disable(dev);
        return err;
 }
 
        return err;
 }
 
@@ -818,6 +842,7 @@ static int adm5120_if_stop(struct net_device *dev)
        int i;
 
        netif_stop_queue(dev);
        int i;
 
        netif_stop_queue(dev);
+       adm5120_if_napi_disable(dev);
 
        /* disable port if not assigned to other devices */
        t = sw_read_reg(SWITCH_REG_PORT_CONF0);
 
        /* disable port if not assigned to other devices */
        t = sw_read_reg(SWITCH_REG_PORT_CONF0);
@@ -843,6 +868,7 @@ static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
        struct adm5120_if_priv *priv = netdev_priv(dev);
        unsigned int entry;
        unsigned long data;
        struct adm5120_if_priv *priv = netdev_priv(dev);
        unsigned int entry;
        unsigned long data;
+       int i;
 
        /* lock switch irq */
        spin_lock_irq(&tx_lock);
 
        /* lock switch irq */
        spin_lock_irq(&tx_lock);
@@ -865,7 +891,7 @@ static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
        data |= DESC_ADDR(skb->data);
 
        desc->misc =
        data |= DESC_ADDR(skb->data);
 
        desc->misc =
-           ((skb->len<ETH_ZLEN?ETH_ZLEN:skb->len) << DESC_PKTLEN_SHIFT) |
+           ((skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len) << DESC_PKTLEN_SHIFT) |
            (0x1 << priv->vlan_no);
 
        desc->buflen = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
            (0x1 << priv->vlan_no);
 
        desc->buflen = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
@@ -875,8 +901,11 @@ static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
 
        cur_txl++;
        if (cur_txl == dirty_txl + TX_QUEUE_LEN) {
 
        cur_txl++;
        if (cur_txl == dirty_txl + TX_QUEUE_LEN) {
-               /* FIXME: stop queue for all devices */
-               netif_stop_queue(dev);
+               for (i = 0; i < SWITCH_NUM_PORTS; i++) {
+                       if (!adm5120_devs[i])
+                               continue;
+                       netif_stop_queue(adm5120_devs[i]);
+               }
        }
 
        dev->trans_start = jiffies;
        }
 
        dev->trans_start = jiffies;
@@ -888,7 +917,7 @@ static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
 
 static void adm5120_if_tx_timeout(struct net_device *dev)
 {
 
 static void adm5120_if_tx_timeout(struct net_device *dev)
 {
-       SW_INFO("TX timeout on %s\n",dev->name);
+       SW_INFO("TX timeout on %s\n", dev->name);
 }
 
 static void adm5120_if_set_multicast_list(struct net_device *dev)
 }
 
 static void adm5120_if_set_multicast_list(struct net_device *dev)
@@ -933,10 +962,10 @@ static void adm5120_if_set_multicast_list(struct net_device *dev)
        /* to the CPU, the Bridge Test Mode has to be activated.               */
 
        /* Check if there is any vlan in promisc mode. */
        /* to the CPU, the Bridge Test Mode has to be activated.               */
 
        /* Check if there is any vlan in promisc mode. */
-       if (t & (SWITCH_PORTS_NOCPU << CPUP_CONF_DUNP_SHIFT))
-               t &= ~CPUP_CONF_BTM; /* Disable Bridge Testing Mode */
-       else
+       if (~t & (SWITCH_PORTS_NOCPU << CPUP_CONF_DUNP_SHIFT))
                t |= CPUP_CONF_BTM;  /* Enable Bridge Testing Mode */
                t |= CPUP_CONF_BTM;  /* Enable Bridge Testing Mode */
+       else
+               t &= ~CPUP_CONF_BTM; /* Disable Bridge Testing Mode */
 
        sw_write_reg(SWITCH_REG_CPUP_CONF, t);
 
 
        sw_write_reg(SWITCH_REG_CPUP_CONF, t);
 
@@ -944,9 +973,12 @@ static void adm5120_if_set_multicast_list(struct net_device *dev)
 
 static int adm5120_if_set_mac_address(struct net_device *dev, void *p)
 {
 
 static int adm5120_if_set_mac_address(struct net_device *dev, void *p)
 {
-       struct sockaddr *addr = p;
+       int ret;
+
+       ret = eth_mac_addr(dev, p);
+       if (ret)
+               return ret;
 
 
-       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
        adm5120_write_mac(dev);
        return 0;
 }
        adm5120_write_mac(dev);
        return 0;
 }
@@ -958,7 +990,7 @@ static int adm5120_if_do_ioctl(struct net_device *dev, struct ifreq *rq,
        struct adm5120_sw_info info;
        struct adm5120_if_priv *priv = netdev_priv(dev);
 
        struct adm5120_sw_info info;
        struct adm5120_if_priv *priv = netdev_priv(dev);
 
-       switch(cmd) {
+       switch (cmd) {
        case SIOCGADMINFO:
                info.magic = 0x5120;
                info.ports = adm5120_nrdevs;
        case SIOCGADMINFO:
                info.magic = 0x5120;
                info.ports = adm5120_nrdevs;
@@ -988,6 +1020,18 @@ static int adm5120_if_do_ioctl(struct net_device *dev, struct ifreq *rq,
        return 0;
 }
 
        return 0;
 }
 
+static const struct net_device_ops adm5120sw_netdev_ops = {
+       .ndo_open               = adm5120_if_open,
+       .ndo_stop               = adm5120_if_stop,
+       .ndo_start_xmit         = adm5120_if_hard_start_xmit,
+       .ndo_set_multicast_list = adm5120_if_set_multicast_list,
+       .ndo_do_ioctl           = adm5120_if_do_ioctl,
+       .ndo_tx_timeout         = adm5120_if_tx_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = adm5120_if_set_mac_address,
+};
+
 static struct net_device *adm5120_if_alloc(void)
 {
        struct net_device *dev;
 static struct net_device *adm5120_if_alloc(void)
 {
        struct net_device *dev;
@@ -997,22 +1041,17 @@ static struct net_device *adm5120_if_alloc(void)
        if (!dev)
                return NULL;
 
        if (!dev)
                return NULL;
 
+       priv = netdev_priv(dev);
+       priv->dev = dev;
+
        dev->irq                = ADM5120_IRQ_SWITCH;
        dev->irq                = ADM5120_IRQ_SWITCH;
-       dev->open               = adm5120_if_open;
-       dev->hard_start_xmit    = adm5120_if_hard_start_xmit;
-       dev->stop               = adm5120_if_stop;
-       dev->set_multicast_list = adm5120_if_set_multicast_list;
-       dev->do_ioctl           = adm5120_if_do_ioctl;
-       dev->tx_timeout         = adm5120_if_tx_timeout;
-       dev->watchdog_timeo     = TX_TIMEOUT;
-       dev->set_mac_address    = adm5120_if_set_mac_address;
+       dev->netdev_ops         = &adm5120sw_netdev_ops;
+       dev->watchdog_timeo     = TX_TIMEOUT;
+
 #ifdef CONFIG_ADM5120_SWITCH_NAPI
 #ifdef CONFIG_ADM5120_SWITCH_NAPI
-       dev->poll               = adm5120_if_poll;
-       dev->weight             = 64;
+       netif_napi_add(dev, &priv->napi, adm5120_if_poll, 64);
 #endif
 
 #endif
 
-       SET_MODULE_OWNER(dev);
-
        return dev;
 }
 
        return dev;
 }
 
@@ -1168,6 +1207,6 @@ module_init(adm5120_switch_mod_init);
 module_exit(adm5120_switch_mod_exit);
 
 MODULE_LICENSE("GPL v2");
 module_exit(adm5120_switch_mod_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
 MODULE_DESCRIPTION(DRV_DESC);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION(DRV_DESC);
 MODULE_VERSION(DRV_VERSION);
This page took 0.03387 seconds and 4 git commands to generate.