* (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
-#include <asm/arch/uengine.h>
-#include <asm/mach-types.h>
+#include <asm/hardware/uengine.h>
#include <asm/io.h>
#include "ixp2400_rx.ucode"
#include "ixp2400_tx.ucode"
#include "ixpdev_priv.h"
#include "ixpdev.h"
+#define DRV_MODULE_VERSION "0.2"
+
static int nds_count;
static struct net_device **nds;
static int nds_open;
}
-static int ixpdev_rx(struct net_device *dev, int *budget)
+static int ixpdev_rx(struct net_device *dev, int processed, int budget)
{
- while (*budget > 0) {
+ while (processed < budget) {
struct ixpdev_rx_desc *desc;
struct sk_buff *skb;
void *buf;
if (unlikely(!netif_running(nds[desc->channel])))
goto err;
- skb = dev_alloc_skb(desc->pkt_length + 2);
+ skb = netdev_alloc_skb(dev, desc->pkt_length + 2);
if (likely(skb != NULL)) {
- skb->dev = nds[desc->channel];
skb_reserve(skb, 2);
- eth_copy_and_sum(skb, buf, desc->pkt_length, 0);
+ skb_copy_to_linear_data(skb, buf, desc->pkt_length);
skb_put(skb, desc->pkt_length);
- skb->protocol = eth_type_trans(skb, skb->dev);
+ skb->protocol = eth_type_trans(skb, nds[desc->channel]);
- skb->dev->last_rx = jiffies;
+ dev->last_rx = jiffies;
netif_receive_skb(skb);
}
err:
ixp2000_reg_write(RING_RX_PENDING, _desc);
- dev->quota--;
- (*budget)--;
+ processed++;
}
- return 1;
+ return processed;
}
/* dev always points to nds[0]. */
-static int ixpdev_poll(struct net_device *dev, int *budget)
+static int ixpdev_poll(struct napi_struct *napi, int budget)
{
- /* @@@ Have to stop polling when nds[0] is administratively
- * downed while we are polling. */
+ struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi);
+ struct net_device *dev = ip->dev;
+ int rx;
+
+ rx = 0;
do {
ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
- if (ixpdev_rx(dev, budget))
- return 1;
+ rx = ixpdev_rx(dev, rx, budget);
+ if (rx >= budget)
+ break;
} while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
- return 0;
+ return rx;
}
static void ixpdev_tx_complete(void)
}
}
-static irqreturn_t ixpdev_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ixpdev_interrupt(int irq, void *dev_id)
{
u32 status;
* Any of the eight receive units signaled RX?
*/
if (status & 0x00ff) {
+ struct net_device *dev = nds[0];
+ struct ixpdev_priv *ip = netdev_priv(dev);
+
ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
- if (likely(netif_rx_schedule_test(nds[0]))) {
- __netif_rx_schedule(nds[0]);
+ if (likely(napi_schedule_prep(&ip->napi))) {
+ __netif_rx_schedule(dev, &ip->napi);
} else {
printk(KERN_CRIT "ixp2000: irq while polling!!\n");
}
return IRQ_HANDLED;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ixpdev_poll_controller(struct net_device *dev)
+{
+ disable_irq(IRQ_IXP2000_THDA0);
+ ixpdev_interrupt(IRQ_IXP2000_THDA0, dev);
+ enable_irq(IRQ_IXP2000_THDA0);
+}
+#endif
+
static int ixpdev_open(struct net_device *dev)
{
struct ixpdev_priv *ip = netdev_priv(dev);
int err;
+ napi_enable(&ip->napi);
if (!nds_open++) {
err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
- SA_SHIRQ, "ixp2000_eth", nds);
+ IRQF_SHARED, "ixp2000_eth", nds);
if (err) {
nds_open--;
+ napi_disable(&ip->napi);
return err;
}
struct ixpdev_priv *ip = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&ip->napi);
set_port_admin_status(ip->channel, 0);
if (!--nds_open) {
return NULL;
dev->hard_start_xmit = ixpdev_xmit;
- dev->poll = ixpdev_poll;
dev->open = ixpdev_open;
dev->stop = ixpdev_close;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = ixpdev_poll_controller;
+#endif
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->weight = 64;
ip = netdev_priv(dev);
+ ip->dev = dev;
+ netif_napi_add(dev, &ip->napi, ixpdev_poll, 64);
ip->channel = channel;
ip->tx_queue_entries = 0;
int i;
int err;
- if (RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192) {
- static void __too_many_rx_or_tx_buffers(void);
- __too_many_rx_or_tx_buffers();
- }
+ BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192);
+
+ printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION);
nds_count = __nds_count;
nds = __nds;
}
}
+ for (i = 0; i < nds_count; i++) {
+ printk(KERN_INFO "%s: IXP2000 MSF ethernet (port %d), "
+ "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", nds[i]->name, i,
+ nds[i]->dev_addr[0], nds[i]->dev_addr[1],
+ nds[i]->dev_addr[2], nds[i]->dev_addr[3],
+ nds[i]->dev_addr[4], nds[i]->dev_addr[5]);
+ }
+
return 0;
err_free_tx: