OpenCloudOS-Kernel/drivers/net/ixp2000/ixpdev.c

417 lines
9.8 KiB
C
Raw Normal View History

[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
/*
* IXP2000 MSF network device driver
* Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
* Dedicated to Marija Kulikova.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#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/hardware/uengine.h>
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
#include <asm/mach-types.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"
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
static int nds_count;
static struct net_device **nds;
static int nds_open;
static void (*set_port_admin_status)(int port, int up);
static struct ixpdev_rx_desc * const rx_desc =
(struct ixpdev_rx_desc *)(IXP2000_SRAM0_VIRT_BASE + RX_BUF_DESC_BASE);
static struct ixpdev_tx_desc * const tx_desc =
(struct ixpdev_tx_desc *)(IXP2000_SRAM0_VIRT_BASE + TX_BUF_DESC_BASE);
static int tx_pointer;
static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ixpdev_priv *ip = netdev_priv(dev);
struct ixpdev_tx_desc *desc;
int entry;
if (unlikely(skb->len > PAGE_SIZE)) {
/* @@@ Count drops. */
dev_kfree_skb(skb);
return 0;
}
entry = tx_pointer;
tx_pointer = (tx_pointer + 1) % TX_BUF_COUNT;
desc = tx_desc + entry;
desc->pkt_length = skb->len;
desc->channel = ip->channel;
skb_copy_and_csum_dev(skb, phys_to_virt(desc->buf_addr));
dev_kfree_skb(skb);
ixp2000_reg_write(RING_TX_PENDING,
TX_BUF_DESC_BASE + (entry * sizeof(struct ixpdev_tx_desc)));
dev->trans_start = jiffies;
local_irq_disable();
ip->tx_queue_entries++;
if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN)
netif_stop_queue(dev);
local_irq_enable();
return 0;
}
static int ixpdev_rx(struct net_device *dev, int *budget)
{
while (*budget > 0) {
struct ixpdev_rx_desc *desc;
struct sk_buff *skb;
void *buf;
u32 _desc;
_desc = ixp2000_reg_read(RING_RX_DONE);
if (_desc == 0)
return 0;
desc = rx_desc +
((_desc - RX_BUF_DESC_BASE) / sizeof(struct ixpdev_rx_desc));
buf = phys_to_virt(desc->buf_addr);
if (desc->pkt_length < 4 || desc->pkt_length > PAGE_SIZE) {
printk(KERN_ERR "ixp2000: rx err, length %d\n",
desc->pkt_length);
goto err;
}
if (desc->channel < 0 || desc->channel >= nds_count) {
printk(KERN_ERR "ixp2000: rx err, channel %d\n",
desc->channel);
goto err;
}
/* @@@ Make FCS stripping configurable. */
desc->pkt_length -= 4;
if (unlikely(!netif_running(nds[desc->channel])))
goto err;
skb = dev_alloc_skb(desc->pkt_length + 2);
if (likely(skb != NULL)) {
skb_reserve(skb, 2);
eth_copy_and_sum(skb, buf, desc->pkt_length, 0);
skb_put(skb, desc->pkt_length);
skb->protocol = eth_type_trans(skb, nds[desc->channel]);
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
skb->dev->last_rx = jiffies;
netif_receive_skb(skb);
}
err:
ixp2000_reg_write(RING_RX_PENDING, _desc);
dev->quota--;
(*budget)--;
}
return 1;
}
/* dev always points to nds[0]. */
static int ixpdev_poll(struct net_device *dev, int *budget)
{
/* @@@ Have to stop polling when nds[0] is administratively
* downed while we are polling. */
do {
ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
if (ixpdev_rx(dev, budget))
return 1;
} while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
netif_rx_complete(dev);
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
return 0;
}
static void ixpdev_tx_complete(void)
{
int channel;
u32 wake;
wake = 0;
while (1) {
struct ixpdev_priv *ip;
u32 desc;
int entry;
desc = ixp2000_reg_read(RING_TX_DONE);
if (desc == 0)
break;
/* @@@ Check whether entries come back in order. */
entry = (desc - TX_BUF_DESC_BASE) / sizeof(struct ixpdev_tx_desc);
channel = tx_desc[entry].channel;
if (channel < 0 || channel >= nds_count) {
printk(KERN_ERR "ixp2000: txcomp channel index "
"out of bounds (%d, %.8i, %d)\n",
channel, (unsigned int)desc, entry);
continue;
}
ip = netdev_priv(nds[channel]);
if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN)
wake |= 1 << channel;
ip->tx_queue_entries--;
}
for (channel = 0; wake != 0; channel++) {
if (wake & (1 << channel)) {
netif_wake_queue(nds[channel]);
wake &= ~(1 << channel);
}
}
}
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 21:55:46 +08:00
static irqreturn_t ixpdev_interrupt(int irq, void *dev_id)
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
{
u32 status;
status = ixp2000_reg_read(IXP2000_IRQ_THD_STATUS_A_0);
if (status == 0)
return IRQ_NONE;
/*
* Any of the eight receive units signaled RX?
*/
if (status & 0x00ff) {
ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
if (likely(__netif_rx_schedule_prep(nds[0]))) {
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
__netif_rx_schedule(nds[0]);
} else {
printk(KERN_CRIT "ixp2000: irq while polling!!\n");
}
}
/*
* Any of the eight transmit units signaled TXdone?
*/
if (status & 0xff00) {
ixp2000_reg_wrb(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0xff00);
ixpdev_tx_complete();
}
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
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
static int ixpdev_open(struct net_device *dev)
{
struct ixpdev_priv *ip = netdev_priv(dev);
int err;
if (!nds_open++) {
err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
IRQF_SHARED, "ixp2000_eth", nds);
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
if (err) {
nds_open--;
return err;
}
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0xffff);
}
set_port_admin_status(ip->channel, 1);
netif_start_queue(dev);
return 0;
}
static int ixpdev_close(struct net_device *dev)
{
struct ixpdev_priv *ip = netdev_priv(dev);
netif_stop_queue(dev);
set_port_admin_status(ip->channel, 0);
if (!--nds_open) {
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0xffff);
free_irq(IRQ_IXP2000_THDA0, nds);
}
return 0;
}
struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
{
struct net_device *dev;
struct ixpdev_priv *ip;
dev = alloc_etherdev(sizeof_priv);
if (dev == NULL)
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
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
dev->weight = 64;
ip = netdev_priv(dev);
ip->channel = channel;
ip->tx_queue_entries = 0;
return dev;
}
int ixpdev_init(int __nds_count, struct net_device **__nds,
void (*__set_port_admin_status)(int port, int up))
{
int i;
int err;
BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192);
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION);
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
nds_count = __nds_count;
nds = __nds;
set_port_admin_status = __set_port_admin_status;
for (i = 0; i < RX_BUF_COUNT; i++) {
void *buf;
buf = (void *)get_zeroed_page(GFP_KERNEL);
if (buf == NULL) {
err = -ENOMEM;
while (--i >= 0)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
goto err_out;
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
}
rx_desc[i].buf_addr = virt_to_phys(buf);
rx_desc[i].buf_length = PAGE_SIZE;
}
/* @@@ Maybe we shouldn't be preallocating TX buffers. */
for (i = 0; i < TX_BUF_COUNT; i++) {
void *buf;
buf = (void *)get_zeroed_page(GFP_KERNEL);
if (buf == NULL) {
err = -ENOMEM;
while (--i >= 0)
free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
goto err_free_rx;
}
tx_desc[i].buf_addr = virt_to_phys(buf);
}
/* 256 entries, ring status set means 'empty', base address 0x0000. */
ixp2000_reg_write(RING_RX_PENDING_BASE, 0x44000000);
ixp2000_reg_write(RING_RX_PENDING_HEAD, 0x00000000);
ixp2000_reg_write(RING_RX_PENDING_TAIL, 0x00000000);
/* 256 entries, ring status set means 'full', base address 0x0400. */
ixp2000_reg_write(RING_RX_DONE_BASE, 0x40000400);
ixp2000_reg_write(RING_RX_DONE_HEAD, 0x00000000);
ixp2000_reg_write(RING_RX_DONE_TAIL, 0x00000000);
for (i = 0; i < RX_BUF_COUNT; i++) {
ixp2000_reg_write(RING_RX_PENDING,
RX_BUF_DESC_BASE + (i * sizeof(struct ixpdev_rx_desc)));
}
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_reg_write(RING_TX_PENDING_TAIL, 0x00000000);
/* 256 entries, ring status set means 'full', base address 0x0c00. */
ixp2000_reg_write(RING_TX_DONE_BASE, 0x40000c00);
ixp2000_reg_write(RING_TX_DONE_HEAD, 0x00000000);
ixp2000_reg_write(RING_TX_DONE_TAIL, 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]);
}
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
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));
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
err_free_rx:
for (i = 0; i < RX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
err_out:
return err;
}
void ixpdev_deinit(void)
{
int i;
/* @@@ Flush out pending packets. */
for (i = 0; i < nds_count; i++)
unregister_netdev(nds[i]);
[PATCH] intel ixp2000 network driver The way the hardware and firmware work is that there is one shared RX queue and IRQ for a number of different network interfaces. Due to this, we would like to process received packets for every interface in the same NAPI poll handler, so we need a pseudo-device to schedule polling on. What the driver currently does is that it always schedules polling for the first network interface in the list, and processes packets for every interface in the poll handler for that first interface -- however, this scheme breaks down if the first network interface happens to not be up, since netif_rx_schedule_prep() checks netif_running(). sky2 apparently has the same issue, and Stephen Hemminger suggested a way to work around this: create a variant of netif_rx_schedule_prep() that does not check netif_running(). I implemented this locally and called it netif_rx_schedule_prep_notup(), and it seems to work well, but it's something that probably not everyone would be happy with. The ixp2000 is an ARM CPU with a high-speed network interface in the CPU itself (full duplex 4Gb/s or 10Gb/s depending on the IXP model.) The CPU package also contains 8 or 16 (again depending on the IXP model) 'microengines', which are somewhat primitive but very fast and efficient processor cores which can be used to offload various things from the main CPU. This driver makes the high-speed network interface in the CPU visible and usable as a regular linux network device. Currently, it only supports the Radisys ENP2611 IXP board, but adding support for other board types should be fairly easy. Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
2005-11-12 01:23:13 +08:00
ixp2000_uengine_stop_contexts(1, 0xff);
ixp2000_uengine_stop_contexts(0, 0xff);
ixp2000_uengine_reset(0x3);
for (i = 0; i < TX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr));
for (i = 0; i < RX_BUF_COUNT; i++)
free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr));
}