switch driver cleanup, 3rd phase
authorGabor Juhos <juhosg@openwrt.org>
Tue, 16 Oct 2007 13:12:51 +0000 (13:12 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Tue, 16 Oct 2007 13:12:51 +0000 (13:12 +0000)
SVN-Revision: 9334

target/linux/adm5120/files/drivers/net/adm5120sw.c

index 987e1de3119084c712c68e739ae3573c56a3098f..e354a35a610bd6c789f1add29b2552e4a75afc1b 100644 (file)
@@ -163,7 +163,6 @@ static spinlock_t sw_lock = SPIN_LOCK_UNLOCKED;
 static spinlock_t poll_lock = SPIN_LOCK_UNLOCKED;
 
 static struct net_device sw_dev;
-static struct net_device *poll_dev;
 
 /* ------------------------------------------------------------------------ */
 
@@ -458,31 +457,6 @@ static int adm5120_switch_rx(int limit)
 }
 
 
-static int adm5120_switch_poll(struct net_device *dev, int *budget)
-{
-       int limit = min(dev->quota, *budget);
-       int done;
-       u32 status;
-
-       done = adm5120_switch_rx(limit);
-
-       *budget -= done;
-       dev->quota -= done;
-
-       status = sw_int_status() & SWITCH_INTS_POLL;
-       if ((done < limit) && (!status)) {
-               spin_lock_irq(&poll_lock);
-               SW_DBG("disable polling mode for %s\n", poll_dev->name);
-               netif_rx_complete(poll_dev);
-               sw_int_unmask(SWITCH_INTS_POLL);
-               poll_dev = NULL;
-               spin_unlock_irq(&poll_lock);
-               return 0;
-       }
-
-       return 1;
-}
-
 static void adm5120_switch_tx(void)
 {
        unsigned int entry;
@@ -517,6 +491,28 @@ static void adm5120_switch_tx(void)
        }
 }
 
+static int adm5120_if_poll(struct net_device *dev, int *budget)
+{
+       int limit = min(dev->quota, *budget);
+       int done;
+       u32 status;
+
+       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", poll_dev->name);
+               netif_rx_complete(dev);
+               sw_int_unmask(SWITCH_INTS_POLL);
+               return 0;
+       }
+
+       return 1;
+}
+
 static irqreturn_t adm5120_poll_irq(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
@@ -529,19 +525,9 @@ static irqreturn_t adm5120_poll_irq(int irq, void *dev_id)
 
        sw_dump_intr_mask("poll ints", status);
 
-       if (!netif_running(dev)) {
-               SW_DBG("device %s is not running\n", dev->name);
-               return IRQ_NONE;
-       }
-
-       spin_lock(&poll_lock);
-       if (!poll_dev) {
-               SW_DBG("enable polling mode for %s\n", dev->name);
-               poll_dev = dev;
-               sw_int_mask(SWITCH_INTS_POLL);
-               netif_rx_schedule(poll_dev);
-       }
-       spin_unlock(&poll_lock);
+       SW_DBG("enable polling mode for %s\n", dev->name);
+       sw_int_mask(SWITCH_INTS_POLL);
+       netif_rx_schedule(dev);
 
        return IRQ_HANDLED;
 }
@@ -605,12 +591,143 @@ static void adm5120_set_bw(char *matrix)
                sw_read_reg(SWITCH_REG_BW_CNTL1));
 }
 
-static int adm5120_switch_open(struct net_device *dev)
+static void adm5120_switch_tx_ring_reset(struct dma_desc *desc,
+               struct sk_buff **skbl, int num)
+{
+       memset(desc, 0, num * sizeof(*desc));
+       desc[num-1].buf1 |= DESC_EOR;
+       memset(skbl, 0, sizeof(struct skb*)*num);
+
+       cur_txl = 0;
+       dirty_txl = 0;
+}
+
+static void adm5120_switch_rx_ring_reset(struct dma_desc *desc,
+               struct sk_buff **skbl, int num)
+{
+       int i;
+
+       memset(desc, 0, num * sizeof(*desc));
+       for (i = 0; i < num; i++) {
+               skbl[i] = dev_alloc_skb(SKB_ALLOC_LEN);
+               if (!skbl[i]) {
+                       i = num;
+                       break;
+               }
+               skb_reserve(skbl[i], SKB_RESERVE_LEN);
+               adm5120_rx_dma_update(&desc[i], skbl[i], (num-1==i));
+       }
+
+       cur_rxl = 0;
+       dirty_rxl = 0;
+}
+
+static int adm5120_switch_tx_ring_alloc(void)
+{
+       int err;
+
+       txl_descs = dma_alloc_coherent(NULL, TX_DESCS_SIZE, &txl_descs_dma,
+                                       GFP_ATOMIC);
+       if (!txl_descs) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       txl_skbuff = kzalloc(TX_SKBS_SIZE, GFP_KERNEL);
+       if (!txl_skbuff) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       return 0;
+
+err:
+       return err;
+}
+
+static void adm5120_switch_tx_ring_free(void)
+{
+       int i;
+
+       if (txl_skbuff) {
+               for (i = 0; i < TX_RING_SIZE; i++)
+                       if (txl_skbuff[i])
+                               kfree_skb(txl_skbuff[i]);
+               kfree(txl_skbuff);
+       }
+
+       if (txl_descs)
+               dma_free_coherent(NULL, TX_DESCS_SIZE, txl_descs,
+                       txl_descs_dma);
+}
+
+static int adm5120_switch_rx_ring_alloc(void)
+{
+       int err;
+       int i;
+
+       /* init RX ring */
+       rxl_descs = dma_alloc_coherent(NULL, RX_DESCS_SIZE, &rxl_descs_dma,
+                                       GFP_ATOMIC);
+       if (!rxl_descs) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       rxl_skbuff = kzalloc(RX_SKBS_SIZE, GFP_KERNEL);
+       if (!rxl_skbuff) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               struct sk_buff *skb;
+               skb = alloc_skb(SKB_ALLOC_LEN, GFP_ATOMIC);
+               if (!skb) {
+                       err = -ENOMEM;
+                       goto err;
+               }
+               rxl_skbuff[i] = skb;
+               skb_reserve(skb, SKB_RESERVE_LEN);
+       }
+
+       return 0;
+
+err:
+       return err;
+}
+
+static void adm5120_switch_rx_ring_free(void)
+{
+       int i;
+
+       if (rxl_skbuff) {
+               for (i = 0; i < RX_RING_SIZE; i++)
+                       if (rxl_skbuff[i])
+                               kfree_skb(rxl_skbuff[i]);
+               kfree(rxl_skbuff);
+       }
+
+       if (rxl_descs)
+               dma_free_coherent(NULL, RX_DESCS_SIZE, rxl_descs,
+                       rxl_descs_dma);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int adm5120_if_open(struct net_device *dev)
 {
        u32 t;
+       int err;
        int i;
 
-       netif_start_queue(dev);
+       err = request_irq(dev->irq, adm5120_poll_irq,
+               (IRQF_SHARED | IRQF_DISABLED), dev->name, dev);
+       if (err) {
+               SW_ERR("unable to get irq for %s\n", dev->name);
+               goto err;
+       }
+
        if (!sw_used++)
                /* enable interrupts on first open */
                sw_int_unmask(SWITCH_INTS_USED);
@@ -623,16 +740,20 @@ static int adm5120_switch_open(struct net_device *dev)
        }
        sw_write_reg(SWITCH_REG_PORT_CONF0, t);
 
+       netif_start_queue(dev);
+
        return 0;
+
+err:
+       return err;
 }
 
-static int adm5120_switch_stop(struct net_device *dev)
+static int adm5120_if_stop(struct net_device *dev)
 {
        u32 t;
        int i;
 
-       if (!--sw_used)
-               sw_int_mask(SWITCH_INTS_USED);
+       netif_stop_queue(dev);
 
        /* disable port if not assigned to other devices */
        t = sw_read_reg(SWITCH_REG_PORT_CONF0);
@@ -643,11 +764,16 @@ static int adm5120_switch_stop(struct net_device *dev)
        }
        sw_write_reg(SWITCH_REG_PORT_CONF0, t);
 
-       netif_stop_queue(dev);
+       if (!--sw_used)
+               sw_int_mask(SWITCH_INTS_USED);
+
+       free_irq(dev->irq, dev);
+
        return 0;
 }
 
-static int adm5120_sw_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
+               struct net_device *dev)
 {
        struct dma_desc *desc;
        struct adm5120_sw *priv = netdev_priv(dev);
@@ -695,7 +821,7 @@ static int adm5120_sw_start_xmit(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
-static void adm5120_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);
 }
@@ -769,7 +895,7 @@ static void adm5120_write_mac(struct net_device *dev)
        while (!(sw_read_reg(SWITCH_REG_MAC_WT0) & MAC_WT0_MWD));
 }
 
-static int adm5120_sw_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;
 
@@ -778,7 +904,7 @@ static int adm5120_sw_set_mac_address(struct net_device *dev, void *p)
        return 0;
 }
 
-static int adm5120_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int adm5120_if_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        int err;
        struct adm5120_sw_info info;
@@ -827,29 +953,30 @@ static int adm5120_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        return 0;
 }
 
-static void adm5120_dma_tx_init(struct dma_desc *desc, struct sk_buff **skbl,
-               int num)
+static struct net_device *adm5120_if_alloc(void)
 {
-       memset(desc, 0, num * sizeof(*desc));
-       desc[num-1].buf1 |= DESC_EOR;
-       memset(skbl, 0, sizeof(struct skb*)*num);
-}
-
-static void adm5120_dma_rx_init(struct dma_desc *desc, struct sk_buff **skbl,
-               int num)
-{
-       int i;
-
-       memset(desc, 0, num * sizeof(*desc));
-       for (i=0; i<num; i++) {
-               skbl[i] = dev_alloc_skb(SKB_ALLOC_LEN);
-               if (!skbl[i]) {
-                       i=num;
-                       break;
-               }
-               skb_reserve(skbl[i], SKB_RESERVE_LEN);
-               adm5120_rx_dma_update(&desc[i], skbl[i], (num-1==i));
-       }
+       struct net_device *dev;
+       struct adm5120_sw *priv;
+
+       dev = alloc_etherdev(sizeof(*priv));
+       if (!dev)
+               return NULL;
+
+       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_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->poll               = adm5120_if_poll;
+       dev->weight             = 64;
+
+       SET_MODULE_OWNER(dev);
+
+       return dev;
 }
 
 static void adm5120_switch_cleanup(void)
@@ -863,41 +990,18 @@ static void adm5120_switch_cleanup(void)
                struct net_device *dev = adm5120_devs[i];
                if (dev) {
                        unregister_netdev(dev);
-                       free_irq(ADM5120_IRQ_SWITCH, dev);
                        free_netdev(dev);
                }
        }
 
-       /* cleanup TX ring */
-       if (txl_skbuff) {
-               for (i = 0; i < TX_RING_SIZE; i++)
-                       if (txl_skbuff[i])
-                               kfree_skb(txl_skbuff[i]);
-               kfree(txl_skbuff);
-       }
-
-       if (txl_descs)
-               dma_free_coherent(NULL, TX_DESCS_SIZE, txl_descs,
-                       txl_descs_dma);
-
-       /* cleanup RX ring */
-       if (rxl_skbuff) {
-               for (i = 0; i < RX_RING_SIZE; i++)
-                       if (rxl_skbuff[i])
-                               kfree_skb(rxl_skbuff[i]);
-               kfree(rxl_skbuff);
-       }
-
-       if (rxl_descs)
-               dma_free_coherent(NULL, RX_DESCS_SIZE, rxl_descs,
-                       rxl_descs_dma);
+       adm5120_switch_tx_ring_free();
+       adm5120_switch_rx_ring_free();
 
        free_irq(ADM5120_IRQ_SWITCH, &sw_dev);
 }
 
 static int __init adm5120_switch_init(void)
 {
-       struct net_device *dev;
        u32 t;
        int i, err;
 
@@ -939,49 +1043,16 @@ static int __init adm5120_switch_init(void)
        sw_int_mask(SWITCH_INTS_ALL);
        sw_int_ack(SWITCH_INTS_ALL);
 
-       /* init RX ring */
-       cur_rxl = dirty_rxl = 0;
-       rxl_descs = dma_alloc_coherent(NULL, RX_DESCS_SIZE, &rxl_descs_dma,
-                                       GFP_ATOMIC);
-       if (!rxl_descs) {
-               err = -ENOMEM;
-               goto err;
-       }
-
-       rxl_skbuff = kzalloc(RX_SKBS_SIZE, GFP_KERNEL);
-       if (!rxl_skbuff) {
-               err = -ENOMEM;
+       err = adm5120_switch_rx_ring_alloc();
+       if (err)
                goto err;
-       }
-
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               struct sk_buff *skb;
-               skb = alloc_skb(SKB_ALLOC_LEN, GFP_ATOMIC);
-               if (!skb) {
-                       err = -ENOMEM;
-                       goto err;
-               }
-               rxl_skbuff[i] = skb;
-               skb_reserve(skb, SKB_RESERVE_LEN);
-       }
 
-       /* init TX ring */
-       cur_txl = dirty_txl = 0;
-       txl_descs = dma_alloc_coherent(NULL, TX_DESCS_SIZE, &txl_descs_dma,
-                                       GFP_ATOMIC);
-       if (!txl_descs) {
-               err = -ENOMEM;
+       err = adm5120_switch_tx_ring_alloc();
+       if (err)
                goto err;
-       }
 
-       txl_skbuff = kzalloc(TX_SKBS_SIZE, GFP_KERNEL);
-       if (!txl_skbuff) {
-               err = -ENOMEM;
-               goto err;
-       }
-
-       adm5120_dma_tx_init(txl_descs, txl_skbuff, TX_RING_SIZE);
-       adm5120_dma_rx_init(rxl_descs, rxl_skbuff, RX_RING_SIZE);
+       adm5120_switch_tx_ring_reset(txl_descs, txl_skbuff, TX_RING_SIZE);
+       adm5120_switch_rx_ring_reset(rxl_descs, rxl_skbuff, RX_RING_SIZE);
 
        sw_write_reg(SWITCH_REG_SHDA, 0);
        sw_write_reg(SWITCH_REG_SLDA, KSEG1ADDR(txl_descs));
@@ -989,35 +1060,19 @@ static int __init adm5120_switch_init(void)
        sw_write_reg(SWITCH_REG_RLDA, KSEG1ADDR(rxl_descs));
 
        for (i = 0; i < SWITCH_NUM_PORTS; i++) {
-               adm5120_devs[i] = alloc_etherdev(sizeof(struct adm5120_sw));
-               if (!adm5120_devs[i]) {
+               struct net_device *dev;
+               struct adm5120_sw *priv;
+
+               dev = adm5120_if_alloc();
+               if (!dev) {
                        err = -ENOMEM;
                        goto err;
                }
 
-               dev = adm5120_devs[i];
-               err = request_irq(ADM5120_IRQ_SWITCH, adm5120_poll_irq,
-                       (IRQF_SHARED | IRQF_DISABLED), dev->name, dev);
-               if (err) {
-                       SW_ERR("unable to get irq for %s\n", dev->name);
-                       goto err;
-               }
+               adm5120_devs[i] = dev;
+               priv = netdev_priv(dev);
 
-               SET_MODULE_OWNER(dev);
-               memset(netdev_priv(dev), 0, sizeof(struct adm5120_sw));
-               ((struct adm5120_sw*)netdev_priv(dev))->port = i;
-               dev->base_addr = ADM5120_SWITCH_BASE;
-               dev->irq = ADM5120_IRQ_SWITCH;
-               dev->open = adm5120_switch_open;
-               dev->hard_start_xmit = adm5120_sw_start_xmit;
-               dev->stop = adm5120_switch_stop;
-               dev->set_multicast_list = adm5120_set_multicast_list;
-               dev->do_ioctl = adm5120_do_ioctl;
-               dev->tx_timeout = adm5120_tx_timeout;
-               dev->watchdog_timeo = TX_TIMEOUT;
-               dev->set_mac_address = adm5120_sw_set_mac_address;
-               dev->poll = adm5120_switch_poll;
-               dev->weight = 64;
+               priv->port = i;
 
                memcpy(dev->dev_addr, adm5120_eth_macs[i], 6);
                adm5120_write_mac(dev);
@@ -1028,7 +1083,6 @@ static int __init adm5120_switch_init(void)
                                        dev->name, err);
                        goto err;
                }
-               SW_INFO("%s created for switch port%d\n", dev->name, i);
        }
 
        /* setup vlan/port mapping after devs are filled up */