X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/23d61f22e9a68a7873626df4a01c60794f1acb7a..6d3f4634c4838127804c54973f052d63e1a7cab3:/target/linux/adm5120/files/drivers/net/adm5120sw.c?ds=sidebyside diff --git a/target/linux/adm5120/files/drivers/net/adm5120sw.c b/target/linux/adm5120/files/drivers/net/adm5120sw.c index c8c3f1d5b..7acc84d24 100644 --- a/target/linux/adm5120/files/drivers/net/adm5120sw.c +++ b/target/linux/adm5120/files/drivers/net/adm5120sw.c @@ -1,7 +1,7 @@ /* * ADM5120 built-in ethernet switch driver * - * Copyright (C) 2007 Gabor Juhos + * Copyright (C) 2007-2008 Gabor Juhos * * This code was based on a driver for Linux 2.6.xx by Jeroen Vreeken. * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005 @@ -24,26 +24,24 @@ #include #include #include +#include +#include #include #include #include -#include -#include - #include -#include -#include -#include -#include +#include +#include +#include #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 @@ -93,8 +91,14 @@ /* ------------------------------------------------------------------------ */ struct adm5120_if_priv { + struct net_device *dev; + unsigned int vlan_no; unsigned int port_mask; + +#ifdef CONFIG_ADM5120_SWITCH_NAPI + struct napi_struct napi; +#endif }; struct dma_desc { @@ -333,7 +337,6 @@ static void sw_dump_regs(void) SW_DBG("rlda: %08X\n", t); } - /* ------------------------------------------------------------------------ */ 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); -#ifdef CONFIG_ADM5120_SWITCH_USE_NAPI +#ifdef CONFIG_ADM5120_SWITCH_NAPI netif_receive_skb(skb); #else netif_rx(skb); @@ -495,9 +498,11 @@ static void adm5120_switch_tx(void) } #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; @@ -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); - *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); - netif_rx_complete(dev); + netif_rx_complete(dev, napi); 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; } -#endif /* CONFIG_ADM5120_SWITCH_USE_NAPI */ +#endif /* CONFIG_ADM5120_SWITCH_NAPI */ static irqreturn_t adm5120_switch_irq(int irq, void *dev_id) @@ -541,10 +543,12 @@ static irqreturn_t adm5120_switch_irq(int irq, void *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); - netif_rx_schedule(dev); + netif_rx_schedule(dev, &priv->napi); } #else sw_int_ack(status); @@ -779,12 +783,31 @@ 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; + adm5120_if_napi_enable(dev); + err = request_irq(dev->irq, adm5120_switch_irq, (IRQF_SHARED | IRQF_DISABLED), dev->name, dev); if (err) { @@ -809,6 +832,7 @@ static int adm5120_if_open(struct net_device *dev) return 0; err: + adm5120_if_napi_disable(dev); return err; } @@ -818,6 +842,7 @@ static int adm5120_if_stop(struct net_device *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); @@ -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; + int i; /* lock switch irq */ spin_lock_irq(&tx_lock); @@ -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) { - /* 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; @@ -997,6 +1026,9 @@ static struct net_device *adm5120_if_alloc(void) if (!dev) return NULL; + priv = netdev_priv(dev); + priv->dev = dev; + dev->irq = ADM5120_IRQ_SWITCH; dev->open = adm5120_if_open; dev->hard_start_xmit = adm5120_if_hard_start_xmit; @@ -1006,13 +1038,11 @@ static struct net_device *adm5120_if_alloc(void) dev->tx_timeout = adm5120_if_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->set_mac_address = adm5120_if_set_mac_address; + #ifdef CONFIG_ADM5120_SWITCH_NAPI - dev->poll = adm5120_if_poll; - dev->weight = 64; + netif_napi_add(dev, &priv->napi, adm5120_if_poll, 64); #endif - SET_MODULE_OWNER(dev); - return dev; } @@ -1168,6 +1198,6 @@ module_init(adm5120_switch_mod_init); module_exit(adm5120_switch_mod_exit); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Gabor Juhos "); +MODULE_AUTHOR("Gabor Juhos "); MODULE_DESCRIPTION(DRV_DESC); MODULE_VERSION(DRV_VERSION);