#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
-#include <asm/arch/uengine.h>
+#include <asm/hardware/uengine.h>
#include <asm/mach-types.h>
#include <asm/io.h>
#include "ixp2400_rx.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;
return 0;
}
-/* @@@ Ugly hack. */
-static inline int netif_rx_schedule_prep_notup(struct net_device *dev)
-{
- return !test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state);
-}
-
static void ixpdev_tx_complete(void)
{
int channel;
*/
if (status & 0x00ff) {
ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
- if (likely(netif_rx_schedule_prep_notup(nds[0]))) {
+ if (likely(__netif_rx_schedule_prep(nds[0]))) {
__netif_rx_schedule(nds[0]);
} 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, NULL);
+ enable_irq(IRQ_IXP2000_THDA0);
+}
+#endif
+
static int ixpdev_open(struct net_device *dev)
{
struct ixpdev_priv *ip = netdev_priv(dev);
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;
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;
set_port_admin_status = __set_port_admin_status;
- for (i = 0; i < nds_count; i++) {
- err = register_netdev(nds[i]);
- if (err) {
- while (--i >= 0)
- unregister_netdev(nds[i]);
- goto err_out;
- }
- }
-
for (i = 0; i < RX_BUF_COUNT; i++) {
void *buf;
err = -ENOMEM;
while (--i >= 0)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
- goto err_unregister;
+ goto err_out;
}
rx_desc[i].buf_addr = virt_to_phys(buf);
rx_desc[i].buf_length = PAGE_SIZE;
ixp2000_uengine_load(0, &ixp2400_rx);
ixp2000_uengine_start_contexts(0, 0xff);
-
/* 256 entries, ring status set means 'empty', base address 0x0800. */
ixp2000_reg_write(RING_TX_PENDING_BASE, 0x44000800);
ixp2000_reg_write(RING_TX_PENDING_HEAD, 0x00000000);
ixp2000_uengine_load(1, &ixp2400_tx);
ixp2000_uengine_start_contexts(1, 0xff);
+ for (i = 0; i < nds_count; i++) {
+ err = register_netdev(nds[i]);
+ if (err) {
+ while (--i >= 0)
+ unregister_netdev(nds[i]);
+ goto err_free_tx;
+ }
+ }
+
+ 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:
+ for (i = 0; i < TX_BUF_COUNT; i++)
+ free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
+
err_free_rx:
for (i = 0; i < RX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
-err_unregister:
- for (i = 0; i < nds_count; i++)
- unregister_netdev(nds[i]);
-
err_out:
return err;
}
/* @@@ Flush out pending packets. */
+ for (i = 0; i < nds_count; i++)
+ unregister_netdev(nds[i]);
+
ixp2000_uengine_stop_contexts(1, 0xff);
ixp2000_uengine_stop_contexts(0, 0xff);
ixp2000_uengine_reset(0x3);
for (i = 0; i < RX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
-
- for (i = 0; i < nds_count; i++)
- unregister_netdev(nds[i]);
}