patch-2.3.46 linux/drivers/net/yellowfin.c
Next file: linux/drivers/pci/pcisyms.c
Previous file: linux/drivers/net/wan/cosa.c
Back to the patch index
Back to the overall index
- Lines: 1309
- Date:
Tue Feb 15 13:47:36 2000
- Orig file:
v2.3.45/linux/drivers/net/yellowfin.c
- Orig date:
Sat Feb 12 11:22:11 2000
diff -u --recursive --new-file v2.3.45/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
@@ -1,6 +1,6 @@
/* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */
/*
- Written 1997-1998 by Donald Becker.
+ Written 1997-1999 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
@@ -17,13 +17,13 @@
*/
static const char *version =
-"yellowfin.c:v1.02 7/26/98 Written by Donald Becker, becker@cesdis.edu\n"
+"yellowfin.c:v1.03a 7/30/99 Written by Donald Becker, becker@cesdis.edu\n"
" http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html\n";
/* A few user-configurable values. */
+static int debug = 1;
static int max_interrupt_work = 20;
-static int min_pci_latency = 64;
static int mtu = 0;
#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
/* System-wide count of bogus-rx frames. */
@@ -50,25 +50,38 @@
static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+/* Do ugly workaround for GX server chipset errata. */
+static int gx_fix = 0;
+
/* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for efficiency.
- Making the Tx ring too large decreases the effectiveness of channel
+ Making the Tx queue too long decreases the effectiveness of channel
bonding and packet priority.
There are no ill effects from too-large receive rings. */
#define TX_RING_SIZE 16
-#define RX_RING_SIZE 32
+#define TX_QUEUE_SIZE 12 /* Must be > 4 && <= TX_RING_SIZE */
+#define RX_RING_SIZE 64
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT ((2000*HZ)/1000)
+#define TX_TIMEOUT (2*HZ)
+
+#define yellowfin_debug debug
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/config.h>
+#include <linux/version.h>
#include <linux/module.h>
+#include <linux/modversions.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
-#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
@@ -76,20 +89,20 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/bitops.h>
#include <asm/unaligned.h>
+#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#define RUN_AT(x) (jiffies + (x))
+/* Condensed operations for readability.
+ Compatibility defines are now in drv_compat.h */
-/* The PCI I/O space extent. */
-#define YELLOWFIN_TOTAL_SIZE 0x100
+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-int yellowfin_debug = 1;
/*
Theory of Operation
@@ -172,31 +185,49 @@
/* A few values that may be tweaked. */
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-#ifndef PCI_VENDOR_ID_PKT_ENG /* To be defined in linux/pci.h */
-#define PCI_VENDOR_ID_PKT_ENG 0x1000 /* Hmm, likely number.. */
-#define PCI_DEVICE_ID_SYM58C885 0x0701
-#define PCI_DEVICE_ID_YELLOWFIN 0x0702
-#endif
-
/* The rest of these values should never change. */
-static void yellowfin_timer(unsigned long data);
+enum capability_flags {
+ HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
+ HasMACAddrBug=32, /* Really only on early revs. */
+};
+
+
+/* The PCI I/O space extent. */
+#define YELLOWFIN_SIZE 0x100
+
+#define YELLOWFIN_MODULE_NAME "yellowfin"
+#define PFX YELLOWFIN_MODULE_NAME ": "
+
+
+typedef enum {
+ YELLOWFIN_GNIC,
+ SYM83C885,
+} chip_t;
-enum capability_flags {HasMII=1, FullTxStatus=2};
-static struct chip_info {
- u16 vendor_id, device_id, device_id_mask, pci_flags;
+
+struct chip_info {
const char *name;
- void (*media_timer)(unsigned long data);
- u32 chip_rev; /* As read from ChipRev, not PCI dev ID. */
int flags;
-} chip_tbl[] = {
- {0x1000, 0x0702, 0xffff, 0, "Yellowfin G-NIC Gbit Ethernet",
- yellowfin_timer, 0x0702, FullTxStatus},
- {0x1000, 0x0701, 0xffff, 0, "Symbios SYM83C885",
- yellowfin_timer, 0x0701, HasMII},
- {0,},
};
+
+/* index by chip_t */
+static struct chip_info chip_info[] = {
+ {"Yellowfin G-NIC Gigabit Ethernet",
+ FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug},
+ {"Symbios SYM83C885", HasMII },
+};
+
+
+static struct pci_device_id yellowfin_pci_tbl[] __devinitdata = {
+ { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, YELLOWFIN_GNIC },
+ { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SYM83C885 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl);
+
+
/* Offsets to the Yellowfin registers. Various sizes and alignments. */
enum yellowfin_offsets {
TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C,
@@ -204,7 +235,8 @@
RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C,
RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58,
EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86,
- ChipRev=0x8C, DMACtrl=0x90, Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4,
+ ChipRev=0x8C, DMACtrl=0x90, TxThreshold=0x94,
+ Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4,
MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC,
MII_Status=0xAE,
RxDepth=0xB8, FlowCtrl=0xBC,
@@ -213,29 +245,35 @@
EEFeature=0xF5,
};
-/* The Yellowfin Rx and Tx buffer descriptors. */
+/* The Yellowfin Rx and Tx buffer descriptors.
+ Elements are written as 32 bit for endian portability. */
struct yellowfin_desc {
- u16 request_cnt;
- u16 cmd;
+ u32 dbdma_cmd;
u32 addr;
u32 branch_addr;
- u16 result_cnt;
- u16 status;
+ u32 result_status;
};
struct tx_status_words {
+#if defined(__powerpc__)
+ u16 tx_errs;
+ u16 tx_cnt;
+ u16 paused;
+ u16 total_tx_cnt;
+#else /* Little endian chips. */
u16 tx_cnt;
u16 tx_errs;
u16 total_tx_cnt;
u16 paused;
+#endif
};
/* Bits in yellowfin_desc.cmd */
enum desc_cmd_bits {
- CMD_TX_PKT=0x1000, CMD_RX_BUF=0x2000, CMD_TXSTATUS=0x3000,
- CMD_NOP=0x6000, CMD_STOP=0x7000,
- BRANCH_ALWAYS=0x0C, INTR_ALWAYS=0x30, WAIT_ALWAYS=0x03,
- BRANCH_IFTRUE=0x04,
+ CMD_TX_PKT=0x10000000, CMD_RX_BUF=0x20000000, CMD_TXSTATUS=0x30000000,
+ CMD_NOP=0x60000000, CMD_STOP=0x70000000,
+ BRANCH_ALWAYS=0x0C0000, INTR_ALWAYS=0x300000, WAIT_ALWAYS=0x030000,
+ BRANCH_IFTRUE=0x040000,
};
/* Bits in yellowfin_desc.status */
@@ -247,6 +285,7 @@
IntrTxDone=0x10, IntrTxInvalid=0x20, IntrTxPCIFault=0x40,IntrTxPCIErr=0x80,
IntrEarlyRx=0x100, IntrWakeup=0x200, };
+#define PRIV_ALIGN 31 /* Required alignment mask */
struct yellowfin_private {
/* Descriptor rings first for alignment. Tx requires a second descriptor
for status. */
@@ -254,21 +293,23 @@
struct yellowfin_desc tx_ring[TX_RING_SIZE*2];
const char *product_name;
struct net_device *next_module;
+ void *priv_addr; /* Unaligned address for kfree */
/* The addresses of receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[TX_RING_SIZE];
struct tx_status_words tx_status[TX_RING_SIZE];
struct timer_list timer; /* Media selection timer. */
- struct enet_statistics stats;
- spinlock_t lock;
+ struct net_device_stats stats;
/* Frequently used and paired value: keep adjacent for cache effect. */
- int chip_id;
+ struct pci_dev *pci_dev;
+ int chip_id, flags;
struct yellowfin_desc *rx_head_desc;
- struct tx_status_words *tx_tail_desc;
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
- unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
+ struct tx_status_words *tx_tail_desc;
+ unsigned int cur_tx, dirty_tx;
+ int tx_threshold;
unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int duplex_lock:1;
@@ -279,19 +320,21 @@
u16 advertising; /* NWay media advertisement */
unsigned char phys[2]; /* MII device addresses. */
u32 pad[4]; /* Used for 32-byte alignment */
+ spinlock_t lock;
};
+
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(min_pci_latency, "i");
MODULE_PARM(mtu, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(gx_fix, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-static struct net_device *yellowfin_probe1(long ioaddr, int irq, int chip_id, int options);
+
static int read_eeprom(long ioaddr, int location);
static int mdio_read(long ioaddr, int phy_id, int location);
static void mdio_write(long ioaddr, int phy_id, int location, int value);
@@ -307,197 +350,17 @@
static int yellowfin_rx(struct net_device *dev);
static void yellowfin_error(struct net_device *dev, int intr_status);
static int yellowfin_close(struct net_device *dev);
-static struct enet_statistics *yellowfin_get_stats(struct net_device *dev);
+static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-
-
-/* A list of all installed Yellowfin devices, for removing the driver module. */
-static struct net_device *root_yellowfin_dev = NULL;
-
-static int __init yellowfin_probe(void)
-{
- int cards_found = 0;
- int pci_index = 0;
- unsigned char pci_bus, pci_device_fn;
-
- if ( ! pci_present())
- return -ENODEV;
-
- for (;pci_index < 0xff; pci_index++) {
- u8 pci_latency;
- u16 pci_command, new_command, vendor, device;
- int chip_idx;
- int irq;
- long ioaddr;
- struct pci_dev *pdev;
-
- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
- pci_index,
- &pci_bus, &pci_device_fn)
- != PCIBIOS_SUCCESSFUL)
- break;
-
- pdev = pci_find_slot (pci_bus, pci_device_fn);
- if (!pdev) break;
- vendor = pdev->vendor;
- device = pdev->device;
-
- for (chip_idx = 0; chip_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor == chip_tbl[chip_idx].vendor_id
- && (device & chip_tbl[chip_idx].device_id_mask) ==
- chip_tbl[chip_idx].device_id)
- break;
- if (chip_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
- continue;
-
- {
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->resource[0].start;
- irq = pdev->irq;
- }
-
- if (yellowfin_debug > 2)
- printk(KERN_INFO "Found %s at I/O %#lx, IRQ %d.\n",
- chip_tbl[chip_idx].name, ioaddr, irq);
-
- if (check_region(ioaddr, YELLOWFIN_TOTAL_SIZE))
- continue;
-
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled the"
- " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
- pci_bus, pci_device_fn, pci_command, new_command);
- pci_write_config_word(pdev, PCI_COMMAND, new_command);
- }
-
- if(yellowfin_probe1(ioaddr, irq, chip_idx, cards_found))
- {
- /* Get and check the bus-master and latency values. */
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < min_pci_latency) {
- printk(KERN_INFO " PCI latency timer (CFLT) is "
- "unreasonably low at %d. Setting to %d clocks.\n",
- pci_latency, min_pci_latency);
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency);
- } else if (yellowfin_debug > 1)
- printk(KERN_INFO " PCI latency timer (CFLT) is %#x.\n",
- pci_latency);
- cards_found++;
- }
- }
-
- return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device *yellowfin_probe1(long ioaddr, int irq, int chip_id, int card_idx)
-{
- static int did_version = 0; /* Already printed version info. */
- struct yellowfin_private *yp;
- int option, i;
- struct net_device *dev;
-
- if (yellowfin_debug > 0 && did_version++ == 0)
- printk(version);
-
- dev = init_etherdev(NULL, sizeof(struct yellowfin_private));
-
- printk(KERN_INFO "%s: %s type %8x at 0x%lx, ",
- dev->name, chip_tbl[chip_id].name, inl(ioaddr + ChipRev), ioaddr);
-
- if (inw(ioaddr + ChipRev) == 0x0702)
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
- else {
- int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i);
- }
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-
- /* Reset the chip. */
- outl(0x80000000, ioaddr + DMACtrl);
-
- /* We do a request_region() only to register /proc/ioports info. */
- request_region(ioaddr, YELLOWFIN_TOTAL_SIZE, dev->name);
-
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
- /* Make certain the descriptor lists are aligned. */
- yp = (void *)(((long)kmalloc(sizeof(*yp), GFP_KERNEL) + 31) & ~31);
- memset(yp, 0, sizeof(*yp));
- dev->priv = yp;
-
- yp->next_module = root_yellowfin_dev;
- root_yellowfin_dev = dev;
-
- yp->chip_id = chip_id;
- yp->lock = SPIN_LOCK_UNLOCKED;
-
- option = card_idx < MAX_UNITS ? options[card_idx] : 0;
- if (dev->mem_start)
- option = dev->mem_start;
-
- /* The lower four bits are the media type. */
- if (option > 0) {
- if (option & 0x200)
- yp->full_duplex = 1;
- yp->default_port = option & 15;
- if (yp->default_port)
- yp->medialock = 1;
- }
- if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
- yp->full_duplex = 1;
-
- if (yp->full_duplex)
- yp->duplex_lock = 1;
-
- /* The Yellowfin-specific entries in the device structure. */
- dev->open = &yellowfin_open;
- dev->hard_start_xmit = &yellowfin_start_xmit;
- dev->stop = &yellowfin_close;
- dev->get_stats = &yellowfin_get_stats;
- dev->set_multicast_list = &set_rx_mode;
-#ifdef HAVE_PRIVATE_IOCTL
- dev->do_ioctl = &mii_ioctl;
-#endif
- dev->tx_timeout = yellowfin_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- if (mtu)
- dev->mtu = mtu;
-
- if (chip_tbl[yp->chip_id].flags & HasMII) {
- int phy, phy_idx = 0;
- for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
- int mii_status = mdio_read(ioaddr, phy, 1);
- if (mii_status != 0xffff &&
- mii_status != 0x0000) {
- yp->phys[phy_idx++] = phy;
- yp->advertising = mdio_read(ioaddr, phy, 4);
- printk(KERN_INFO "%s: MII PHY found at address %d, status "
- "0x%4.4x advertising %4.4x.\n",
- dev->name, phy, mii_status, yp->advertising);
- }
- }
- yp->mii_cnt = phy_idx;
- }
-
- return dev;
-}
-static int read_eeprom(long ioaddr, int location)
+static int __devinit read_eeprom(long ioaddr, int location)
{
- int bogus_cnt = 1000;
+ int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */
outb(location, ioaddr + EEAddr);
outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl);
- while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0)
+ while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0)
;
return inb(ioaddr + EERead);
}
@@ -575,13 +438,16 @@
/* Enable automatic generation of flow control frames, period 0xffff. */
outl(0x0030FFFF, ioaddr + FlowCtrl);
+ yp->tx_threshold = 32;
+ outl(yp->tx_threshold, ioaddr + TxThreshold);
+
if (dev->if_port == 0)
dev->if_port = yp->default_port;
- netif_start_queue(dev);
+ netif_start_queue (dev);
/* Setting the Rx mode will start the Rx process. */
- if (yp->chip_id == 0) {
+ if (yp->flags & IsGigabit) {
/* We are always in full-duplex mode with gigabit! */
yp->full_duplex = 1;
outw(0x01CF, ioaddr + Cnfg);
@@ -604,7 +470,7 @@
}
/* Set the timer to check for link beat. */
init_timer(&yp->timer);
- yp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
+ yp->timer.expires = jiffies + 3*HZ;
yp->timer.data = (unsigned long)dev;
yp->timer.function = &yellowfin_timer; /* timer handler */
add_timer(&yp->timer);
@@ -617,7 +483,7 @@
struct net_device *dev = (struct net_device *)data;
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
long ioaddr = dev->base_addr;
- int next_tick = 0;
+ int next_tick = 60*HZ;
if (yellowfin_debug > 3) {
printk(KERN_DEBUG "%s: Yellowfin timer tick, status %8.8x.\n",
@@ -646,10 +512,8 @@
next_tick = 3*HZ;
}
- if (next_tick) {
- yp->timer.expires = RUN_AT(next_tick);
- add_timer(&yp->timer);
- }
+ yp->timer.expires = jiffies + next_tick;
+ add_timer(&yp->timer);
}
static void yellowfin_tx_timeout(struct net_device *dev)
@@ -657,33 +521,37 @@
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
long ioaddr = dev->base_addr;
- printk(KERN_WARNING "%s: Yellowfin transmit timed out, status %8.8x, resetting...\n",
- dev->name, inl(ioaddr));
+ printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx "
+ "status %4.4x, Rx status %4.4x, resetting...\n",
+ dev->name, yp->cur_tx, yp->dirty_tx,
+ inl(ioaddr + TxStatus), inl(ioaddr + RxStatus));
-#ifndef __alpha__
- {
+ /* Note: these should be KERN_DEBUG. */
+ if (yellowfin_debug) {
int i;
- printk(KERN_DEBUG " Rx ring %8.8x: ", (int)yp->rx_ring);
+ printk(KERN_WARNING " Rx ring %p: ", yp->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)yp->rx_ring[i].status);
- printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)yp->tx_ring);
+ printk(" %8.8x", yp->rx_ring[i].result_status);
+ printk("\n"KERN_WARNING" Tx ring %p: ", yp->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
- printk(" %4.4x /%4.4x", yp->tx_status[i].tx_errs, yp->tx_ring[i].status);
+ printk(" %4.4x /%8.8x", yp->tx_status[i].tx_errs,
+ yp->tx_ring[i].result_status);
printk("\n");
}
-#endif
- /* Perhaps we should reinitialize the hardware here. */
- dev->if_port = 0;
- /* Stop and restart the chip's Tx processes . */
-
- /* Trigger an immediate transmit demand. */
-
- dev->trans_start = jiffies;
- yp->stats.tx_errors++;
- return;
-}
+ /* If the hardware is found to hang regularly, we will update the code
+ to reinitialize the chip here. */
+ dev->if_port = 0;
+ /* Wake the potentially-idle transmit channel. */
+ outl(0x10001000, dev->base_addr + TxCtrl);
+ if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
+ netif_wake_queue (dev); /* Typical path */
+
+ dev->trans_start = jiffies;
+ yp->stats.tx_errors++;
+ return;
+}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void yellowfin_init_ring(struct net_device *dev)
@@ -693,62 +561,66 @@
yp->tx_full = 0;
yp->cur_rx = yp->cur_tx = 0;
- yp->dirty_rx = yp->dirty_tx = 0;
+ yp->dirty_tx = 0;
yp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
yp->rx_head_desc = &yp->rx_ring[0];
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb;
-
- yp->rx_ring[i].request_cnt = yp->rx_buf_sz;
- yp->rx_ring[i].cmd = CMD_RX_BUF | INTR_ALWAYS;
+ yp->rx_ring[i].dbdma_cmd =
+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
+ yp->rx_ring[i].branch_addr = virt_to_le32desc(&yp->rx_ring[i+1]);
+ }
+ /* Mark the last entry as wrapping the ring. */
+ yp->rx_ring[i-1].branch_addr = virt_to_le32desc(&yp->rx_ring[0]);
- skb = dev_alloc_skb(yp->rx_buf_sz);
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
yp->rx_skbuff[i] = skb;
- if (skb) {
- skb->dev = dev; /* Mark as being used by this device. */
- skb_reserve(skb, 2); /* 16 byte align the IP header. */
- yp->rx_ring[i].addr = virt_to_bus(skb->tail);
- } else if (yp->dirty_rx == 0)
- yp->dirty_rx = (unsigned int)(0 - RX_RING_SIZE);
- yp->rx_ring[i].branch_addr = virt_to_bus(&yp->rx_ring[i+1]);
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ skb_reserve(skb, 2); /* 16 byte align the IP header. */
+ yp->rx_ring[i].addr = virt_to_le32desc(skb->tail);
}
- /* Mark the last entry as wrapping the ring. */
- yp->rx_ring[i-1].cmd = CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
- yp->rx_ring[i-1].branch_addr = virt_to_bus(&yp->rx_ring[0]);
+ yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-/*#define NO_TXSTATS*/
+#define NO_TXSTATS
#ifdef NO_TXSTATS
/* In this mode the Tx ring needs only a single descriptor. */
for (i = 0; i < TX_RING_SIZE; i++) {
yp->tx_skbuff[i] = 0;
- yp->tx_ring[i].cmd = CMD_STOP;
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
}
- yp->tx_ring[--i].cmd = CMD_STOP | BRANCH_ALWAYS; /* Wrap ring */
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
+ /* Wrap ring */
+ yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[0]);
#else
/* Tx ring needs a pair of descriptors, the second for the status. */
for (i = 0; i < TX_RING_SIZE*2; i++) {
yp->tx_skbuff[i/2] = 0;
- yp->tx_ring[i].cmd = CMD_STOP; /* Branch on Tx error. */
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ /* Branch on Tx error. */
+ yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
i++;
- if (chip_tbl[yp->chip_id].flags & FullTxStatus) {
- yp->tx_ring[i].cmd = CMD_TXSTATUS;
+ if (yp->flags & FullTxStatus) {
+ yp->tx_ring[i].dbdma_cmd =
+ cpu_to_le32(CMD_TXSTATUS | sizeof(yp->tx_status[i]));
yp->tx_ring[i].request_cnt = sizeof(yp->tx_status[i]);
- yp->tx_ring[i].addr = virt_to_bus(&yp->tx_status[i/2]);
+ yp->tx_ring[i].addr = virt_to_le32desc(&yp->tx_status[i/2]);
} else { /* Symbios chips write only tx_errs word. */
- yp->tx_ring[i].cmd = CMD_TXSTATUS | INTR_ALWAYS;
+ yp->tx_ring[i].dbdma_cmd =
+ cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2);
yp->tx_ring[i].request_cnt = 2;
- yp->tx_ring[i].addr = virt_to_bus(&yp->tx_status[i/2].tx_errs);
+ yp->tx_ring[i].addr = virt_to_le32desc(&yp->tx_status[i/2].tx_errs);
}
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]);
}
/* Wrap ring */
- yp->tx_ring[--i].cmd = CMD_TXSTATUS | BRANCH_ALWAYS | INTR_ALWAYS;
- yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);
+ yp->tx_ring[--i].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS);
+ yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[0]);
#endif
yp->tx_tail_desc = &yp->tx_status[0];
return;
@@ -759,6 +631,8 @@
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
unsigned entry;
+ netif_stop_queue (dev);
+
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
@@ -767,34 +641,42 @@
yp->tx_skbuff[entry] = skb;
+ if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */
+ int cacheline_end = (virt_to_bus(skb->data) + skb->len) % 32;
+ /* Fix GX chipset errata. */
+ if (cacheline_end > 24 || cacheline_end == 0)
+ skb->len += 32 - cacheline_end + 1;
+ }
#ifdef NO_TXSTATS
- yp->tx_ring[entry].request_cnt = skb->len;
- yp->tx_ring[entry].addr = virt_to_bus(skb->data);
- yp->tx_ring[entry].status = 0;
+ yp->tx_ring[entry].addr = virt_to_le32desc(skb->data);
+ yp->tx_ring[entry].result_status = 0;
if (entry >= TX_RING_SIZE-1) {
- yp->tx_ring[0].cmd = CMD_STOP; /* New stop command. */
- yp->tx_ring[TX_RING_SIZE-1].cmd = CMD_TX_PKT | BRANCH_ALWAYS;
+ /* New stop command. */
+ yp->tx_ring[0].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->tx_ring[TX_RING_SIZE-1].dbdma_cmd =
+ cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | skb->len);
} else {
- yp->tx_ring[entry+1].cmd = CMD_STOP; /* New stop command. */
- yp->tx_ring[entry].cmd = CMD_TX_PKT | BRANCH_IFTRUE;
+ yp->tx_ring[entry+1].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->tx_ring[entry].dbdma_cmd =
+ cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | skb->len);
}
yp->cur_tx++;
#else
yp->tx_ring[entry<<1].request_cnt = skb->len;
- yp->tx_ring[entry<<1].addr = virt_to_bus(skb->data);
+ yp->tx_ring[entry<<1].addr = virt_to_le32desc(skb->data);
/* The input_last (status-write) command is constant, but we must rewrite
the subsequent 'stop' command. */
yp->cur_tx++;
{
unsigned next_entry = yp->cur_tx % TX_RING_SIZE;
- yp->tx_ring[next_entry<<1].cmd = CMD_STOP;
+ yp->tx_ring[next_entry<<1].dbdma_cmd = cpu_to_le32(CMD_STOP);
}
/* Final step -- overwrite the old 'stop' command. */
- yp->tx_ring[entry<<1].cmd =
- (entry % 6) == 0 ? CMD_TX_PKT | INTR_ALWAYS | BRANCH_IFTRUE :
- CMD_TX_PKT | BRANCH_IFTRUE;
+ yp->tx_ring[entry<<1].dbdma_cmd =
+ cpu_to_le32( ((entry % 6) == 0 ? CMD_TX_PKT|INTR_ALWAYS|BRANCH_IFTRUE :
+ CMD_TX_PKT | BRANCH_IFTRUE) | skb->len);
#endif
/* Non-x86 Todo: explicitly flush cache lines here. */
@@ -802,8 +684,8 @@
/* Wake the potentially-idle transmit channel. */
outl(0x10001000, dev->base_addr + TxCtrl);
- if (yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 1)
- netif_start_queue(dev); /* Typical path */
+ if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
+ netif_start_queue (dev); /* Typical path */
else
yp->tx_full = 1;
dev->trans_start = jiffies;
@@ -853,20 +735,23 @@
#ifdef NO_TXSTATS
for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) {
int entry = yp->dirty_tx % TX_RING_SIZE;
- if (yp->tx_ring[entry].status == 0)
+ if (yp->tx_ring[entry].result_status == 0)
break;
+ yp->stats.tx_bytes += yp->tx_skbuff[entry]->len;
+ yp->stats.tx_packets++;
/* Free the original skb. */
dev_kfree_skb_irq(yp->tx_skbuff[entry]);
yp->tx_skbuff[entry] = 0;
- yp->stats.tx_packets++;
}
- if (yp->tx_full &&
- test_bit(LINK_STATE_XOFF, &dev->flags) &&
- yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 4) {
+ if (yp->tx_full
+ && yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) {
/* The ring is no longer full, clear tbusy. */
yp->tx_full = 0;
- netif_wake_queue (dev);
}
+ if (yp->tx_full)
+ netif_stop_queue(dev);
+ else
+ netif_wake_queue(dev);
#else
if (intr_status & IntrTxDone
|| yp->tx_tail_desc->tx_errs) {
@@ -890,7 +775,7 @@
#endif
if (tx_errs == 0)
break; /* It still hasn't been Txed */
- if (tx_errs & 0xF8100000) {
+ if (tx_errs & 0xF810) {
/* There was an major error, log it. */
#ifndef final_version
if (yellowfin_debug > 1)
@@ -914,10 +799,10 @@
#ifdef ETHER_STATS
if (tx_errs & 0x0400) yp->stats.tx_deferred++;
#endif
+ yp->stats.tx_bytes += yp->tx_skbuff[entry]->len;
yp->stats.collisions += tx_errs & 15;
yp->stats.tx_packets++;
}
-
/* Free the original skb. */
dev_kfree_skb_irq(yp->tx_skbuff[entry]);
yp->tx_skbuff[entry] = 0;
@@ -933,13 +818,15 @@
}
#endif
- if (yp->tx_full &&
- test_bit(LINK_STATE_XOFF, &dev->flags) &&
- yp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
+ if (yp->tx_full
+ && yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) {
/* The ring is no longer full, clear tbusy. */
yp->tx_full = 0;
- netif_wake_queue (dev);
}
+ if (yp->tx_full)
+ netif_stop_queue(dev);
+ else
+ netif_wake_queue(dev);
yp->dirty_tx = dirty_tx;
yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE];
@@ -964,15 +851,14 @@
/* Code that should never be run! Perhaps remove after testing.. */
{
static int stopit = 10;
- if ((!test_bit(LINK_STATE_START, &dev->state)) && --stopit < 0) {
+ if ((!(test_bit(LINK_STATE_START, &dev->state))) && --stopit < 0) {
printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
dev->name);
free_irq(irq, dev);
}
}
- spin_lock (&yp->lock);
- return;
+ spin_unlock (&yp->lock);
}
/* This routine is logically part of the interrupt handler, but separated
@@ -984,21 +870,22 @@
int boguscnt = 20;
if (yellowfin_debug > 4) {
- printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %4.4x.\n",
- entry, yp->rx_ring[entry].status);
- printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x.\n",
- entry, yp->rx_ring[entry].cmd,
- yp->rx_ring[entry].request_cnt, yp->rx_ring[entry].addr,
- yp->rx_ring[entry].result_cnt, yp->rx_ring[entry].status);
+ printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %8.8x.\n",
+ entry, yp->rx_ring[entry].result_status);
+ printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n",
+ entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr,
+ yp->rx_ring[entry].result_status);
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
- while (yp->rx_head_desc->status) {
+ while (yp->rx_head_desc->result_status) {
struct yellowfin_desc *desc = yp->rx_head_desc;
- u16 desc_status = desc->status;
- int data_size = desc->request_cnt - desc->result_cnt;
- u8 *buf_addr = bus_to_virt(desc->addr);
- s16 frame_status = get_unaligned((s16*)(buf_addr+data_size-2));
+ u16 desc_status = le32_to_cpu(desc->result_status) >> 16;
+ int data_size =
+ (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status))
+ & 0xffff;
+ u8 *buf_addr = le32desc_to_virt(desc->addr);
+ s16 frame_status = get_unaligned((s16*)&(buf_addr[data_size - 2]));
if (yellowfin_debug > 4)
printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n",
@@ -1009,7 +896,7 @@
printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers,"
" status %4.4x!\n", dev->name, desc_status);
yp->stats.rx_length_errors++;
- } else if (yp->chip_id == 0 && (frame_status & 0x0038)) {
+ } else if ((yp->flags & IsGigabit) && (frame_status & 0x0038)) {
/* There was a error. */
if (yellowfin_debug > 3)
printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n",
@@ -1019,7 +906,7 @@
if (frame_status & 0x0008) yp->stats.rx_frame_errors++;
if (frame_status & 0x0010) yp->stats.rx_crc_errors++;
if (frame_status < 0) yp->stats.rx_dropped++;
- } else if (yp->chip_id != 0 &&
+ } else if ( !(yp->flags & IsGigabit) &&
((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
u8 status1 = buf_addr[data_size-2];
u8 status2 = buf_addr[data_size-1];
@@ -1029,14 +916,16 @@
if (status2 & 0x04) yp->stats.rx_crc_errors++;
if (status2 & 0x80) yp->stats.rx_dropped++;
#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
- } else if (memcmp(bus_to_virt(yp->rx_ring[entry].addr),
+ } else if ((yp->flags & HasMACAddrBug) &&
+ memcmp(le32desc_to_virt(yp->rx_ring[entry].addr),
dev->dev_addr, 6) != 0
- && memcmp(bus_to_virt(yp->rx_ring[entry].addr),
+ && memcmp(le32desc_to_virt(yp->rx_ring[entry].addr),
"\377\377\377\377\377\377", 6) != 0) {
- printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
- dev->name, buf_addr[0], buf_addr[1], buf_addr[2],
- buf_addr[3], buf_addr[4], buf_addr[5]);
- bogus_rx++;
+ if (bogus_rx++ == 0)
+ printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:"
+ "%2.2x:%2.2x.\n",
+ dev->name, buf_addr[0], buf_addr[1], buf_addr[2],
+ buf_addr[3], buf_addr[4], buf_addr[5]);
#endif
} else {
struct sk_buff *skb;
@@ -1055,10 +944,10 @@
if (pkt_len > rx_copybreak) {
char *temp = skb_put(skb = yp->rx_skbuff[entry], pkt_len);
#ifndef final_verison /* Remove after testing. */
- if (bus_to_virt(yp->rx_ring[entry].addr) != temp)
+ if (le32desc_to_virt(yp->rx_ring[entry].addr) != temp)
printk(KERN_WARNING "%s: Warning -- the skbuff addresses "
"do not match in yellowfin_rx: %p vs. %p / %p.\n",
- dev->name, bus_to_virt(yp->rx_ring[entry].addr),
+ dev->name, le32desc_to_virt(yp->rx_ring[entry].addr),
skb->head, temp);
#endif
yp->rx_skbuff[entry] = NULL;
@@ -1068,19 +957,19 @@
break;
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align the data fields */
-#if 1
- eth_copy_and_sum(skb, bus_to_virt(yp->rx_ring[entry].addr),
- pkt_len, 0);
+#if 1 || USE_IP_CSUM
+ eth_copy_and_sum(skb, yp->rx_skbuff[entry]->tail, pkt_len, 0);
skb_put(skb, pkt_len);
#else
- memcpy(skb_put(skb, pkt_len),
- bus_to_virt(yp->rx_ring[entry].addr), pkt_len);
+ memcpy(skb_put(skb, pkt_len), yp->rx_skbuff[entry]->tail,
+ pkt_len);
#endif
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
yp->stats.rx_packets++;
+ yp->stats.rx_bytes += pkt_len;
}
entry = (++yp->cur_rx) % RX_RING_SIZE;
yp->rx_head_desc = &yp->rx_ring[entry];
@@ -1088,24 +977,25 @@
/* Refill the Rx ring buffers. */
for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) {
- struct sk_buff *skb;
entry = yp->dirty_rx % RX_RING_SIZE;
if (yp->rx_skbuff[entry] == NULL) {
- skb = dev_alloc_skb(yp->rx_buf_sz);
+ struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
if (skb == NULL)
break; /* Better luck next round. */
+ yp->rx_skbuff[entry] = skb;
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- yp->rx_ring[entry].addr = virt_to_bus(skb->tail);
- yp->rx_skbuff[entry] = skb;
+ yp->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
}
- yp->rx_ring[entry].cmd = CMD_STOP;
- yp->rx_ring[entry].status = 0; /* Clear complete bit. */
+ yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP);
+ yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */
if (entry != 0)
- yp->rx_ring[entry - 1].cmd = CMD_RX_BUF | INTR_ALWAYS;
+ yp->rx_ring[entry - 1].dbdma_cmd =
+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
else
- yp->rx_ring[RX_RING_SIZE - 1].cmd =
- CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;
+ yp->rx_ring[RX_RING_SIZE - 1].dbdma_cmd =
+ cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS
+ | yp->rx_buf_sz);
}
return 0;
@@ -1130,7 +1020,7 @@
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
int i;
- netif_stop_queue(dev);
+ netif_stop_queue (dev);
if (yellowfin_debug > 1) {
printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n",
@@ -1149,16 +1039,14 @@
del_timer(&yp->timer);
-#ifdef __i386__
+#if !defined(final_version) && defined(__i386__)
if (yellowfin_debug > 2) {
printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring));
for (i = 0; i < TX_RING_SIZE*2; i++)
- printk(" %c #%d desc. %4.4x %4.4x %8.8x %8.8x %4.4x %4.4x.\n",
+ printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",
inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
- i, yp->tx_ring[i].cmd,
- yp->tx_ring[i].request_cnt, yp->tx_ring[i].addr,
- yp->tx_ring[i].branch_addr,
- yp->tx_ring[i].result_cnt, yp->tx_ring[i].status);
+ i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,
+ yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);
printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" #%d status %4.4x %4.4x %4.4x %4.4x.\n",
@@ -1167,16 +1055,16 @@
printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring));
for (i = 0; i < RX_RING_SIZE; i++) {
- printk(KERN_DEBUG " %c #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x\n",
+ printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n",
inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
- i, yp->rx_ring[i].cmd,
- yp->rx_ring[i].request_cnt, yp->rx_ring[i].addr,
- yp->rx_ring[i].result_cnt, yp->rx_ring[i].status);
+ i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr,
+ yp->rx_ring[i].result_status);
if (yellowfin_debug > 6) {
- if (*(u8*)yp->rx_ring[i].addr != 0x69) {
+ if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) {
int j;
for (j = 0; j < 0x50; j++)
- printk(" %4.4x", ((u16*)yp->rx_ring[i].addr)[j]);
+ printk(" %4.4x",
+ get_unaligned(((u16*)yp->rx_ring[i].addr) + j));
printk("\n");
}
}
@@ -1188,7 +1076,7 @@
/* Free all the skbuffs in the Rx queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
- yp->rx_ring[i].cmd = CMD_STOP;
+ yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
yp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
if (yp->rx_skbuff[i]) {
dev_kfree_skb(yp->rx_skbuff[i]);
@@ -1212,7 +1100,7 @@
return 0;
}
-static struct enet_statistics *yellowfin_get_stats(struct net_device *dev)
+static struct net_device_stats *yellowfin_get_stats(struct net_device *dev)
{
struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
return &yp->stats;
@@ -1267,7 +1155,7 @@
i++, mclist = mclist->next) {
/* Due to a bug in the early chip versions, multiple filter
slots must be set for each address. */
- if (yp->chip_id == 0) {
+ if (yp->flags & HasMulticastBug) {
set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,
hash_table);
set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,
@@ -1303,7 +1191,7 @@
data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
return 0;
@@ -1314,40 +1202,201 @@
#endif /* HAVE_PRIVATE_IOCTL */
-/* An additional parameter that may be passed in... */
-static int debug = -1;
-
-static int __init yellowfin_init_module(void)
+static int __devinit yellowfin_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- if (debug >= 0)
- yellowfin_debug = debug;
+ struct net_device *dev;
+ struct yellowfin_private *yp;
+ int option, i, irq;
+ int flags, chip_idx;
+ static int find_cnt = 0;
+ long ioaddr;
+
+ chip_idx = ent->driver_data;
+ flags = chip_info[chip_idx].flags;
- return yellowfin_probe();
+ dev = init_etherdev(NULL, 0);
+ if (!dev) {
+ printk (KERN_ERR PFX "cannot allocate ethernet device\n");
+ return -ENOMEM;
+ }
+
+ dev->priv = kmalloc(sizeof(*yp) + PRIV_ALIGN, GFP_KERNEL);
+ if (!dev->priv)
+ goto err_out_free_netdev;
+ yp = (void *)(((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN);
+ memset(yp, 0, sizeof(*yp));
+ yp->priv_addr = dev->priv; /* store real addr for kfree */
+ dev->priv = yp; /* use aligned addr */
+
+ if (!request_region (pci_resource_start (pdev, 0),
+ YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {
+ printk (KERN_ERR PFX "cannot obtain I/O port region\n");
+ goto err_out_free_priv;
+ }
+ if (!request_mem_region (pci_resource_start (pdev, 1),
+ YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {
+ printk (KERN_ERR PFX "cannot obtain MMIO region\n");
+ goto err_out_free_pio_region;
+ }
+
+ pci_enable_device (pdev);
+ pci_set_master (pdev);
+
+#ifdef USE_IO_OPS
+ ioaddr = pci_resource_start (pdev, 0);
+#else
+ ioaddr = pci_resource_start (pdev, 1);
+#endif
+ irq = pdev->irq;
+
+ printk(KERN_INFO "%s: %s type %8x at 0x%lx, ",
+ dev->name, chip_info[chip_idx].name, inl(ioaddr + ChipRev), ioaddr);
+
+ if (flags & IsGigabit)
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
+ else {
+ int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i);
+ }
+ for (i = 0; i < 5; i++)
+ printk("%2.2x:", dev->dev_addr[i]);
+ printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+
+ /* Reset the chip. */
+ outl(0x80000000, ioaddr + DMACtrl);
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ pdev->driver_data = dev;
+ yp->chip_id = chip_idx;
+ yp->flags = flags;
+ yp->lock = SPIN_LOCK_UNLOCKED;
+
+ option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
+ if (dev->mem_start)
+ option = dev->mem_start;
+
+ /* The lower four bits are the media type. */
+ if (option > 0) {
+ if (option & 0x200)
+ yp->full_duplex = 1;
+ yp->default_port = option & 15;
+ if (yp->default_port)
+ yp->medialock = 1;
+ }
+ if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
+ yp->full_duplex = 1;
+
+ if (yp->full_duplex)
+ yp->duplex_lock = 1;
+
+ /* The Yellowfin-specific entries in the device structure. */
+ dev->open = &yellowfin_open;
+ dev->hard_start_xmit = &yellowfin_start_xmit;
+ dev->stop = &yellowfin_close;
+ dev->get_stats = &yellowfin_get_stats;
+ dev->set_multicast_list = &set_rx_mode;
+#ifdef HAVE_PRIVATE_IOCTL
+ dev->do_ioctl = &mii_ioctl;
+#endif
+ dev->tx_timeout = yellowfin_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ if (mtu)
+ dev->mtu = mtu;
+
+ if (yp->flags & HasMII) {
+ int phy, phy_idx = 0;
+ for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
+ int mii_status = mdio_read(ioaddr, phy, 1);
+ if (mii_status != 0xffff &&
+ mii_status != 0x0000) {
+ yp->phys[phy_idx++] = phy;
+ yp->advertising = mdio_read(ioaddr, phy, 4);
+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
+ "0x%4.4x advertising %4.4x.\n",
+ dev->name, phy, mii_status, yp->advertising);
+ }
+ }
+ yp->mii_cnt = phy_idx;
+ }
+
+ find_cnt++;
+
+ return 0;
+
+err_out_free_pio_region:
+ release_region (pci_resource_start (pdev, 0), YELLOWFIN_SIZE);
+err_out_free_priv:
+ kfree (dev->priv);
+err_out_free_netdev:
+ unregister_netdev (dev);
+ kfree (dev);
+ return -ENODEV;
}
-static void __exit yellowfin_cleanup_module (void)
+static void __devexit yellowfin_remove_one (struct pci_dev *pdev)
{
- struct net_device *next_dev;
+ struct net_device *dev = pdev->driver_data;
+ struct yellowfin_private *np;
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_yellowfin_dev) {
- next_dev = ((struct yellowfin_private *)root_yellowfin_dev->priv)->next_module;
- unregister_netdev(root_yellowfin_dev);
- release_region(root_yellowfin_dev->base_addr, YELLOWFIN_TOTAL_SIZE);
- kfree(root_yellowfin_dev);
- root_yellowfin_dev = next_dev;
+ if (!dev) {
+ printk (KERN_ERR "remove non-existent device\n");
+ return;
}
+ np = (struct yellowfin_private *) dev->priv;
+
+ unregister_netdev (dev);
+
+#ifdef USE_IO_OPS
+ release_region (dev->base_addr, YELLOWFIN_SIZE);
+#else
+ iounmap ((void *) dev->base_addr);
+ release_mem_region (dev->base_addr, YELLOWFIN_SIZE);
+#endif
+
+ if (np->priv_addr)
+ kfree (np->priv_addr);
+
+ kfree (dev);
+}
+
+
+static struct pci_driver yellowfin_driver = {
+ name: YELLOWFIN_MODULE_NAME,
+ id_table: yellowfin_pci_tbl,
+ probe: yellowfin_init_one,
+ remove: yellowfin_remove_one,
+};
+
+
+static int __init yellowfin_init (void)
+{
+ if (debug) /* Emit version even if no cards detected. */
+ printk(KERN_INFO "%s", version);
+ return pci_register_driver (&yellowfin_driver) > 0 ? 0 : -ENODEV;
+}
+
+
+static void __exit yellowfin_cleanup (void)
+{
+ pci_unregister_driver (&yellowfin_driver);
}
-module_init(yellowfin_init_module);
-module_exit(yellowfin_cleanup_module);
+
+module_init(yellowfin_init);
+module_exit(yellowfin_exit);
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)