/*
* ADM5120 built-in ethernet switch driver
*
- * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ * Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
*
* This code was based on a driver for Linux 2.6.xx by Jeroen Vreeken.
* Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
#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
/* ------------------------------------------------------------------------ */
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 {
SW_DBG("rlda: %08X\n", t);
}
-
/* ------------------------------------------------------------------------ */
static inline void adm5120_rx_dma_update(struct dma_desc *desc,
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);
}
#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;
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;
}
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)
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);
/* ------------------------------------------------------------------------ */
+#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) {
return 0;
err:
+ adm5120_if_napi_disable(dev);
return err;
}
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);
for (i = 0; i < SWITCH_NUM_PORTS; i++) {
if (!adm5120_devs[i])
continue;
- netif_stop_queue(dev);
+ netif_stop_queue(adm5120_devs[i]);
}
}
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;
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;
}