/*
Written 1998-2000 by Donald Becker.
- Current maintainer is Ion Badulescu <ionut@cs.columbia.edu>. Please
+ Current maintainer is Ion Badulescu <ionut ta badula tod org>. Please
send all bug reports to me, and not to Donald Becker, as this code
has been heavily modified from Donald's original version.
- put the chip to a D3 slumber on driver unload
- added config option to enable/disable NAPI
-TODO: bugfixes (no bugs known as of right now)
+ LK1.4.2 (Ion Badulescu)
+ - finally added firmware (GPL'ed by Adaptec)
+ - removed compatibility code for 2.2.x
+
+ LK1.4.2.1 (Ion Badulescu)
+ - fixed 32/64 bit issues on i386 + CONFIG_HIGHMEM
+ - added 32-bit padding to outgoing skb's, removed previous workaround
+
+TODO: - fix forced speed/duplexing code (broken a long time ago, when
+ somebody converted the driver to use the generic MII code)
+ - fix VLAN support
*/
#define DRV_NAME "starfire"
-#define DRV_VERSION "1.03+LK1.4.1"
-#define DRV_RELDATE "February 10, 2002"
+#define DRV_VERSION "1.03+LK1.4.2.1"
+#define DRV_RELDATE "October 3, 2005"
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/uaccess.h>
#include <asm/io.h>
-/*
- * Adaptec's license for their drivers (which is where I got the
- * firmware files) does not allow one to redistribute them. Thus, we can't
- * include the firmware with this driver.
- *
- * However, should a legal-to-distribute firmware become available,
- * the driver developer would need only to obtain the firmware in the
- * form of a C header file.
- * Once that's done, the #undef below must be changed into a #define
- * for this driver to really use the firmware. Note that Rx/Tx
- * hardware TCP checksumming is not possible without the firmware.
- *
- * WANTED: legal firmware to include with this GPL'd driver.
- */
-#undef HAS_FIRMWARE
+#include "starfire_firmware.h"
/*
* The current frame processor firmware fails to checksum a fragment
* of length 1. If and when this is fixed, the #define below can be removed.
*/
#define HAS_BROKEN_FIRMWARE
+
/*
- * Define this if using the driver with the zero-copy patch
+ * If using the broken firmware, data must be padded to the next 32-bit boundary.
*/
-#if defined(HAS_FIRMWARE) && defined(MAX_SKB_FRAGS)
-#define ZEROCOPY
+#ifdef HAS_BROKEN_FIRMWARE
+#define PADDING_MASK 3
#endif
-#ifdef HAS_FIRMWARE
-#include "starfire_firmware.h"
-#endif /* HAS_FIRMWARE */
+/*
+ * Define this if using the driver with the zero-copy patch
+ */
+#define ZEROCOPY
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define VLAN_SUPPORT
The Starfire has a 512 element hash table based on the Ethernet CRC. */
static int multicast_filter_limit = 512;
/* Whether to do TCP/UDP checksums in hardware */
-#ifdef HAS_FIRMWARE
static int enable_hw_cksum = 1;
-#else
-static int enable_hw_cksum = 0;
-#endif
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
/*
* This SUCKS.
* We need a much better method to determine if dma_addr_t is 64-bit.
*/
-#if (defined(__i386__) && defined(CONFIG_HIGHMEM) && (LINUX_VERSION_CODE > 0x20500 || defined(CONFIG_HIGHMEM64G))) || defined(__x86_64__) || defined (__ia64__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
+#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
/* 64-bit dma_addr_t */
#define ADDR_64BITS /* This chip uses 64 bit addresses. */
+#define netdrv_addr_t u64
#define cpu_to_dma(x) cpu_to_le64(x)
#define dma_to_cpu(x) le64_to_cpu(x)
#define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit
#define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit
#define RX_DESC_ADDR_SIZE RxDescAddr64bit
#else /* 32-bit dma_addr_t */
+#define netdrv_addr_t u32
#define cpu_to_dma(x) cpu_to_le32(x)
#define dma_to_cpu(x) le32_to_cpu(x)
#define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit
#define RX_DESC_ADDR_SIZE RxDescAddr32bit
#endif
-#ifdef MAX_SKB_FRAGS
#define skb_first_frag_len(skb) skb_headlen(skb)
#define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1)
-#else /* not MAX_SKB_FRAGS */
-#define skb_first_frag_len(skb) (skb->len)
-#define skb_num_frags(skb) 1
-#endif /* not MAX_SKB_FRAGS */
-
-/* 2.2.x compatibility code */
-#if LINUX_VERSION_CODE < 0x20300
-
-#include "starfire-kcomp22.h"
-
-#else /* LINUX_VERSION_CODE > 0x20300 */
-
-#include <linux/crc32.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-
-#include <linux/if_vlan.h>
-
-#define COMPAT_MOD_INC_USE_COUNT
-#define COMPAT_MOD_DEC_USE_COUNT
-
-#define init_tx_timer(dev, func, timeout) \
- dev->tx_timeout = func; \
- dev->watchdog_timeo = timeout;
-#define kick_tx_timer(dev, func, timeout)
-
-#define netif_start_if(dev)
-#define netif_stop_if(dev)
-
-#define PCI_SLOT_NAME(pci_dev) pci_name(pci_dev)
-
-#endif /* LINUX_VERSION_CODE > 0x20300 */
#ifdef HAVE_NETDEV_POLL
#define init_poll(dev) \
+do { \
dev->poll = &netdev_poll; \
- dev->weight = max_interrupt_work;
+ dev->weight = max_interrupt_work; \
+} while (0)
#define netdev_rx(dev, ioaddr) \
do { \
u32 intr_enable; \
/* Paranoia check */ \
intr_enable = readl(ioaddr + IntrEnable); \
if (intr_enable & (IntrRxDone | IntrRxEmpty)) { \
- printk("%s: interrupt while in polling mode!\n", dev->name); \
+ printk(KERN_INFO "%s: interrupt while in polling mode!\n", dev->name); \
intr_enable &= ~(IntrRxDone | IntrRxEmpty); \
writel(intr_enable, ioaddr + IntrEnable); \
} \
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
MODULE_LICENSE("GPL");
-
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(mtu, "i");
-MODULE_PARM(debug, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(intr_latency, "i");
-MODULE_PARM(small_frames, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(enable_hw_cksum, "i");
+MODULE_VERSION(DRV_VERSION);
+
+module_param(max_interrupt_work, int, 0);
+module_param(mtu, int, 0);
+module_param(debug, int, 0);
+module_param(rx_copybreak, int, 0);
+module_param(intr_latency, int, 0);
+module_param(small_frames, int, 0);
+module_param_array(options, int, NULL, 0);
+module_param_array(full_duplex, int, NULL, 0);
+module_param(enable_hw_cksum, int, 0);
MODULE_PARM_DESC(max_interrupt_work, "Maximum events handled per interrupt");
MODULE_PARM_DESC(mtu, "MTU (all boards)");
MODULE_PARM_DESC(debug, "Debug level (0-6)");
minimum-length padding. It does not use the completion queue
consumer index, but instead checks for non-zero status entries.
-For receive this driver uses type 0/1/2/3 receive descriptors. The driver
+For receive this driver uses type 2/3 receive descriptors. The driver
allocates full frame size skbuffs for the Rx ring buffers, so all frames
should fit in a single descriptor. The driver does not use the completion
queue consumer index, but instead checks for non-zero status entries.
*/
-\f
+
enum chip_capability_flags {CanHaveMII=1, };
u32 timestamp;
};
/* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */
-#ifdef HAS_FIRMWARE
#ifdef VLAN_SUPPORT
typedef struct full_rx_done_desc rx_done_desc;
#define RxComplType RxComplType3
typedef struct csum_rx_done_desc rx_done_desc;
#define RxComplType RxComplType2
#endif /* not VLAN_SUPPORT */
-#else /* not HAS_FIRMWARE */
-#ifdef VLAN_SUPPORT
-typedef struct basic_rx_done_desc rx_done_desc;
-#define RxComplType RxComplType1
-#else /* not VLAN_SUPPORT */
-typedef struct short_rx_done_desc rx_done_desc;
-#define RxComplType RxComplType0
-#endif /* not VLAN_SUPPORT */
-#endif /* not HAS_FIRMWARE */
enum rx_done_bits {
RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,
struct mii_if_info mii_if; /* MII lib hooks/info */
int phy_cnt; /* MII device addresses. */
unsigned char phys[PHY_CNT]; /* MII device addresses. */
+ void __iomem *base;
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct net_device *dev);
static void netdev_media_change(struct net_device *dev);
+static struct ethtool_ops ethtool_ops;
#ifdef VLAN_SUPPORT
static void netdev_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
spin_lock(&np->lock);
if (debug > 2)
static void netdev_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
spin_lock(&np->lock);
if (debug > 1)
static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
spin_lock(&np->lock);
if (debug > 1)
struct net_device *dev;
static int card_idx = -1;
long ioaddr;
+ void __iomem *base;
int drv_flags, io_size;
int boguscnt;
irq = pdev->irq;
- if (pci_request_regions (pdev, dev->name)) {
+ if (pci_request_regions (pdev, DRV_NAME)) {
printk(KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", card_idx);
goto err_out_free_netdev;
}
/* ioremap is borken in Linux-2.2.x/sparc64 */
-#if !defined(CONFIG_SPARC64) || LINUX_VERSION_CODE > 0x20300
- ioaddr = (long) ioremap(ioaddr, io_size);
- if (!ioaddr) {
+ base = ioremap(ioaddr, io_size);
+ if (!base) {
printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",
card_idx, io_size, ioaddr);
goto err_out_free_res;
}
-#endif /* !CONFIG_SPARC64 || Linux 2.3.0+ */
pci_set_master(pdev);
/* enable MWI -- it vastly improves Rx performance on sparc64 */
pci_set_mwi(pdev);
-#ifdef MAX_SKB_FRAGS
- dev->features |= NETIF_F_SG;
-#endif /* MAX_SKB_FRAGS */
#ifdef ZEROCOPY
/* Starfire can do TCP/UDP checksumming */
if (enable_hw_cksum)
- dev->features |= NETIF_F_IP_CSUM;
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
#endif /* ZEROCOPY */
#ifdef VLAN_SUPPORT
dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
/* Serial EEPROM reads are hidden by the hardware. */
for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20 - i);
+ dev->dev_addr[i] = readb(base + EEPROMCtrl + 20 - i);
#if ! defined(final_version) /* Dump the EEPROM contents during development. */
if (debug > 4)
for (i = 0; i < 0x20; i++)
printk("%2.2x%s",
- (unsigned int)readb(ioaddr + EEPROMCtrl + i),
+ (unsigned int)readb(base + EEPROMCtrl + i),
i % 16 != 15 ? " " : "\n");
#endif
/* Issue soft reset */
- writel(MiiSoftReset, ioaddr + TxMode);
+ writel(MiiSoftReset, base + TxMode);
udelay(1000);
- writel(0, ioaddr + TxMode);
+ writel(0, base + TxMode);
/* Reset the chip to erase previous misconfiguration. */
- writel(1, ioaddr + PCIDeviceConfig);
+ writel(1, base + PCIDeviceConfig);
boguscnt = 1000;
while (--boguscnt > 0) {
udelay(10);
- if ((readl(ioaddr + PCIDeviceConfig) & 1) == 0)
+ if ((readl(base + PCIDeviceConfig) & 1) == 0)
break;
}
if (boguscnt == 0)
/* wait a little longer */
udelay(1000);
- dev->base_addr = ioaddr;
+ dev->base_addr = (unsigned long)base;
dev->irq = irq;
- np = dev->priv;
+ np = netdev_priv(dev);
+ np->base = base;
spin_lock_init(&np->lock);
pci_set_drvdata(pdev, dev);
/* The chip-specific entries in the device structure. */
dev->open = &netdev_open;
dev->hard_start_xmit = &start_tx;
- init_tx_timer(dev, tx_timeout, TX_TIMEOUT);
+ dev->tx_timeout = tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
init_poll(dev);
dev->stop = &netdev_close;
dev->get_stats = &get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &netdev_ioctl;
+ SET_ETHTOOL_OPS(dev, ðtool_ops);
if (mtu)
dev->mtu = mtu;
if (register_netdev(dev))
goto err_out_cleardev;
- printk(KERN_INFO "%s: %s at %#lx, ",
- dev->name, netdrv_tbl[chip_idx].name, ioaddr);
+ printk(KERN_INFO "%s: %s at %p, ",
+ dev->name, netdrv_tbl[chip_idx].name, base);
for (i = 0; i < 5; i++)
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
if ((mdio_read(dev, phy, MII_BMCR) & BMCR_RESET) == 0)
break;
if (boguscnt == 0) {
- printk("%s: PHY reset never completed!\n", dev->name);
+ printk("%s: PHY#%d reset never completed!\n", dev->name, phy);
continue;
}
mii_status = mdio_read(dev, phy, MII_BMSR);
err_out_cleardev:
pci_set_drvdata(pdev, NULL);
- iounmap((void *)ioaddr);
+ iounmap(base);
err_out_free_res:
pci_release_regions (pdev);
err_out_free_netdev:
/* Read the MII Management Data I/O (MDIO) interfaces. */
static int mdio_read(struct net_device *dev, int phy_id, int location)
{
- long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *mdio_addr = np->base + MIICtrl + (phy_id<<7) + (location<<2);
int result, boguscnt=1000;
/* ??? Should we add a busy-wait here? */
do
static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
{
- long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *mdio_addr = np->base + MIICtrl + (phy_id<<7) + (location<<2);
writel(value, mdio_addr);
/* The busy-wait will occur before a read. */
}
static int netdev_open(struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
- long ioaddr = dev->base_addr;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
int i, retval;
size_t tx_done_q_size, rx_done_q_size, tx_ring_size, rx_ring_size;
/* Do we ever need to reset the chip??? */
- COMPAT_MOD_INC_USE_COUNT;
-
retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
- if (retval) {
- COMPAT_MOD_DEC_USE_COUNT;
+ if (retval)
return retval;
- }
/* Disable the Rx and Tx, and reset the chip. */
writel(0, ioaddr + GenCtrl);
rx_ring_size = sizeof(struct starfire_rx_desc) * RX_RING_SIZE;
np->queue_mem_size = tx_done_q_size + rx_done_q_size + tx_ring_size + rx_ring_size;
np->queue_mem = pci_alloc_consistent(np->pci_dev, np->queue_mem_size, &np->queue_mem_dma);
- if (np->queue_mem == 0) {
- COMPAT_MOD_DEC_USE_COUNT;
+ if (np->queue_mem == NULL) {
+ free_irq(dev->irq, dev);
return -ENOMEM;
}
writew(0, ioaddr + PerfFilterTable + 8);
for (i = 1; i < 16; i++) {
u16 *eaddrs = (u16 *)dev->dev_addr;
- long setup_frm = ioaddr + PerfFilterTable + i * 16;
+ void __iomem *setup_frm = ioaddr + PerfFilterTable + i * 16;
writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;
writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;
writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl);
- netif_start_if(dev);
netif_start_queue(dev);
if (debug > 1)
writel(ETH_P_8021Q, ioaddr + VlanType);
#endif /* VLAN_SUPPORT */
-#ifdef HAS_FIRMWARE
/* Load Rx/Tx firmware into the frame processors */
for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
writel(firmware_rx[i], ioaddr + RxGfpMem + i * 4);
for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
writel(firmware_tx[i], ioaddr + TxGfpMem + i * 4);
-#endif /* HAS_FIRMWARE */
if (enable_hw_cksum)
/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
writel(TxEnable|TxGFPEnable|RxEnable|RxGFPEnable, ioaddr + GenCtrl);
static void check_duplex(struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
u16 reg0;
int silly_count = 1000;
static void tx_timeout(struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
- long ioaddr = dev->base_addr;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
int old_debug;
printk(KERN_WARNING "%s: Transmit timed out, status %#8.8x, "
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void init_ring(struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
int i;
np->cur_rx = np->cur_tx = np->reap_tx = 0;
np->rx_info[i].skb = skb;
if (skb == NULL)
break;
- np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb->dev = dev; /* Mark as being used by this device. */
/* Grrr, we cannot offset to correctly align the IP header. */
np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid);
}
- writew(i - 1, dev->base_addr + RxDescQIdx);
+ writew(i - 1, np->base + RxDescQIdx);
np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
/* Clear the remainder of the Rx buffer ring. */
static int start_tx(struct sk_buff *skb, struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
unsigned int entry;
u32 status;
int i;
- kick_tx_timer(dev, tx_timeout, TX_TIMEOUT);
-
/*
* be cautious here, wrapping the queue has weird semantics
* and we may not have enough slots even when it seems we do.
}
#if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE)
- {
- int has_bad_length = 0;
-
- if (skb_first_frag_len(skb) == 1)
- has_bad_length = 1;
- else {
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
- if (skb_shinfo(skb)->frags[i].size == 1) {
- has_bad_length = 1;
- break;
- }
- }
-
- if (has_bad_length)
- skb_checksum_help(skb);
+ if (skb->ip_summed == CHECKSUM_HW) {
+ skb = skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK);
+ if (skb == NULL)
+ return NETDEV_TX_OK;
}
#endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
np->tx_info[entry].mapping =
pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE);
} else {
-#ifdef MAX_SKB_FRAGS
skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i - 1];
status |= this_frag->size;
np->tx_info[entry].mapping =
pci_map_single(np->pci_dev, page_address(this_frag->page) + this_frag->page_offset, this_frag->size, PCI_DMA_TODEVICE);
-#endif /* MAX_SKB_FRAGS */
}
np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping);
wmb();
/* Update the producer index. */
- writel(entry * (sizeof(starfire_tx_desc) / 8), dev->base_addr + TxProducerIdx);
+ writel(entry * (sizeof(starfire_tx_desc) / 8), np->base + TxProducerIdx);
/* 4 is arbitrary, but should be ok */
if ((np->cur_tx - np->dirty_tx) + 4 > TX_RING_SIZE)
static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
{
struct net_device *dev = dev_instance;
- struct netdev_private *np;
- long ioaddr;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
int boguscnt = max_interrupt_work;
int consumer;
int tx_status;
int handled = 0;
- ioaddr = dev->base_addr;
- np = dev->priv;
-
do {
u32 intr_status = readl(ioaddr + IntrClear);
np->tx_info[entry].mapping = 0;
np->dirty_tx += np->tx_info[entry].used_slots;
entry = (entry + np->tx_info[entry].used_slots) % TX_RING_SIZE;
-#ifdef MAX_SKB_FRAGS
{
int i;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
entry++;
}
}
-#endif /* MAX_SKB_FRAGS */
+
dev_kfree_skb_irq(skb);
}
np->tx_done_q[np->tx_done].status = 0;
for clarity, code sharing between NAPI/non-NAPI, and better register allocation. */
static int __netdev_rx(struct net_device *dev, int *quota)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
u32 desc_status;
int retcode = 0;
if (debug > 4)
printk(KERN_DEBUG " netdev_rx() status of %d was %#8.8x.\n", np->rx_done, desc_status);
if (!(desc_status & RxOK)) {
- /* There was a error. */
+ /* There was an error. */
if (debug > 2)
printk(KERN_DEBUG " netdev_rx() Rx error was %#8.8x.\n", desc_status);
np->stats.rx_errors++;
pci_dma_sync_single_for_cpu(np->pci_dev,
np->rx_info[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
+ eth_copy_and_sum(skb, np->rx_info[entry].skb->data, pkt_len, 0);
pci_dma_sync_single_for_device(np->pci_dev,
np->rx_info[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
#endif
skb->protocol = eth_type_trans(skb, dev);
-#if defined(HAS_FIRMWARE) || defined(VLAN_SUPPORT)
+#ifdef VLAN_SUPPORT
if (debug > 4)
printk(KERN_DEBUG " netdev_rx() status2 of %d was %#4.4x.\n", np->rx_done, le16_to_cpu(desc->status2));
#endif
-#ifdef HAS_FIRMWARE
if (le16_to_cpu(desc->status2) & 0x0100) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
np->stats.rx_compressed++;
skb->csum = le16_to_cpu(desc->csum);
printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2));
}
-#endif /* HAS_FIRMWARE */
#ifdef VLAN_SUPPORT
if (np->vlgrp && le16_to_cpu(desc->status2) & 0x0200) {
if (debug > 4)
desc->status = 0;
np->rx_done = (np->rx_done + 1) % DONE_Q_SIZE;
}
- writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx);
+ writew(np->rx_done, np->base + CompletionQConsumerIdx);
out:
refill_rx_ring(dev);
static int netdev_poll(struct net_device *dev, int *budget)
{
u32 intr_status;
- long ioaddr = dev->base_addr;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
int retcode = 0, quota = dev->quota;
do {
static void refill_rx_ring(struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
struct sk_buff *skb;
int entry = -1;
if (skb == NULL)
break; /* Better luck next round. */
np->rx_info[entry].mapping =
- pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb->dev = dev; /* Mark as being used by this device. */
np->rx_ring[entry].rxaddr =
cpu_to_dma(np->rx_info[entry].mapping | RxDescValid);
np->rx_ring[entry].rxaddr |= cpu_to_dma(RxDescEndRing);
}
if (entry >= 0)
- writew(entry, dev->base_addr + RxDescQIdx);
+ writew(entry, np->base + RxDescQIdx);
}
static void netdev_media_change(struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
- long ioaddr = dev->base_addr;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
u16 reg0, reg1, reg4, reg5;
u32 new_tx_mode;
u32 new_intr_timer_ctrl;
static void netdev_error(struct net_device *dev, int intr_status)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
/* Came close to underrunning the Tx FIFO, increase threshold. */
if (intr_status & IntrTxDataLow) {
if (np->tx_threshold <= PKT_BUF_SZ / 16) {
- writel(++np->tx_threshold, dev->base_addr + TxThreshold);
+ writel(++np->tx_threshold, np->base + TxThreshold);
printk(KERN_NOTICE "%s: PCI bus congestion, increasing Tx FIFO threshold to %d bytes\n",
dev->name, np->tx_threshold * 16);
} else
static struct net_device_stats *get_stats(struct net_device *dev)
{
- long ioaddr = dev->base_addr;
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
/* This adapter architecture needs no SMP locks. */
np->stats.tx_bytes = readl(ioaddr + 0x57010);
}
-/* Chips may use the upper or lower CRC bits, and may reverse and/or invert
- them. Select the endian-ness that results in minimal calculations.
-*/
static void set_rx_mode(struct net_device *dev)
{
- long ioaddr = dev->base_addr;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
u32 rx_mode = MinVLANPrio;
struct dev_mc_list *mclist;
int i;
#ifdef VLAN_SUPPORT
- struct netdev_private *np = dev->priv;
rx_mode |= VlanMode;
if (np->vlgrp) {
int vlan_count = 0;
- long filter_addr = ioaddr + HashTable + 8;
+ void __iomem *filter_addr = ioaddr + HashTable + 8;
for (i = 0; i < VLAN_VID_MASK; i++) {
if (np->vlgrp->vlan_devices[i]) {
if (vlan_count >= 32)
rx_mode |= AcceptBroadcast|AcceptAllMulticast|PerfectFilter;
} else if (dev->mc_count <= 14) {
/* Use the 16 element perfect filter, skip first two entries. */
- long filter_addr = ioaddr + PerfFilterTable + 2 * 16;
+ void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16;
u16 *eaddrs;
for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2;
i++, mclist = mclist->next) {
rx_mode |= AcceptBroadcast|PerfectFilter;
} else {
/* Must use a multicast hash table. */
- long filter_addr;
+ void __iomem *filter_addr;
u16 *eaddrs;
u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
+ /* The chip uses the upper 9 CRC bits
+ as index into the hash table */
int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
__u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1];
writel(rx_mode, ioaddr + RxFilterMode);
}
+static int check_if_running(struct net_device *dev)
+{
+ if (!netif_running(dev))
+ return -EINVAL;
+ return 0;
+}
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- struct ethtool_cmd ecmd;
- struct netdev_private *np = dev->priv;
-
- if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
- return -EFAULT;
-
- switch (ecmd.cmd) {
- case ETHTOOL_GDRVINFO: {
- struct ethtool_drvinfo info;
- memset(&info, 0, sizeof(info));
- info.cmd = ecmd.cmd;
- strcpy(info.driver, DRV_NAME);
- strcpy(info.version, DRV_VERSION);
- *info.fw_version = 0;
- strcpy(info.bus_info, PCI_SLOT_NAME(np->pci_dev));
- if (copy_to_user(useraddr, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
+ struct netdev_private *np = netdev_priv(dev);
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(np->pci_dev));
+}
- /* get settings */
- case ETHTOOL_GSET: {
- struct ethtool_cmd ecmd = { ETHTOOL_GSET };
- spin_lock_irq(&np->lock);
- mii_ethtool_gset(&np->mii_if, &ecmd);
- spin_unlock_irq(&np->lock);
- if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
- return -EFAULT;
- return 0;
- }
- /* set settings */
- case ETHTOOL_SSET: {
- int r;
- struct ethtool_cmd ecmd;
- if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
- return -EFAULT;
- spin_lock_irq(&np->lock);
- r = mii_ethtool_sset(&np->mii_if, &ecmd);
- spin_unlock_irq(&np->lock);
- check_duplex(dev);
- return r;
- }
- /* restart autonegotiation */
- case ETHTOOL_NWAY_RST: {
- return mii_nway_restart(&np->mii_if);
- }
- /* get link status */
- case ETHTOOL_GLINK: {
- struct ethtool_value edata = {ETHTOOL_GLINK};
- edata.data = mii_link_ok(&np->mii_if);
- if (copy_to_user(useraddr, &edata, sizeof(edata)))
- return -EFAULT;
- return 0;
- }
+static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ spin_lock_irq(&np->lock);
+ mii_ethtool_gset(&np->mii_if, ecmd);
+ spin_unlock_irq(&np->lock);
+ return 0;
+}
- /* get message-level */
- case ETHTOOL_GMSGLVL: {
- struct ethtool_value edata = {ETHTOOL_GMSGLVL};
- edata.data = debug;
- if (copy_to_user(useraddr, &edata, sizeof(edata)))
- return -EFAULT;
- return 0;
- }
- /* set message-level */
- case ETHTOOL_SMSGLVL: {
- struct ethtool_value edata;
- if (copy_from_user(&edata, useraddr, sizeof(edata)))
- return -EFAULT;
- debug = edata.data;
- return 0;
- }
- default:
- return -EOPNOTSUPP;
- }
+static int set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ int res;
+ spin_lock_irq(&np->lock);
+ res = mii_ethtool_sset(&np->mii_if, ecmd);
+ spin_unlock_irq(&np->lock);
+ check_duplex(dev);
+ return res;
}
+static int nway_reset(struct net_device *dev)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ return mii_nway_restart(&np->mii_if);
+}
+
+static u32 get_link(struct net_device *dev)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ return mii_link_ok(&np->mii_if);
+}
+
+static u32 get_msglevel(struct net_device *dev)
+{
+ return debug;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+ debug = val;
+}
+
+static struct ethtool_ops ethtool_ops = {
+ .begin = check_if_running,
+ .get_drvinfo = get_drvinfo,
+ .get_settings = get_settings,
+ .set_settings = set_settings,
+ .nway_reset = nway_reset,
+ .get_link = get_link,
+ .get_msglevel = get_msglevel,
+ .set_msglevel = set_msglevel,
+};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(rq);
int rc;
if (!netif_running(dev))
return -EINVAL;
- if (cmd == SIOCETHTOOL)
- rc = netdev_ethtool_ioctl(dev, rq->ifr_data);
-
- else {
- struct mii_ioctl_data *data = if_mii(rq);
- spin_lock_irq(&np->lock);
- rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
- spin_unlock_irq(&np->lock);
+ spin_lock_irq(&np->lock);
+ rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+ spin_unlock_irq(&np->lock);
- if ((cmd == SIOCSMIIREG) && (data->phy_id == np->phys[0]))
- check_duplex(dev);
- }
+ if ((cmd == SIOCSMIIREG) && (data->phy_id == np->phys[0]))
+ check_duplex(dev);
return rc;
}
static int netdev_close(struct net_device *dev)
{
- long ioaddr = dev->base_addr;
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
int i;
netif_stop_queue(dev);
- netif_stop_if(dev);
if (debug > 1) {
printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n",
np->tx_info[i].skb = NULL;
}
- COMPAT_MOD_DEC_USE_COUNT;
-
return 0;
}
static void __devexit starfire_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct netdev_private *np;
+ struct netdev_private *np = netdev_priv(dev);
if (!dev)
BUG();
- np = dev->priv;
+ unregister_netdev(dev);
+
if (np->queue_mem)
pci_free_consistent(pdev, np->queue_mem_size, np->queue_mem, np->queue_mem_dma);
- unregister_netdev(dev);
/* XXX: add wakeup code -- requires firmware for MagicPacket */
- pci_set_power_state(pdev, 3); /* go to sleep in D3 mode */
+ pci_set_power_state(pdev, PCI_D3hot); /* go to sleep in D3 mode */
pci_disable_device(pdev);
- iounmap((char *)dev->base_addr);
+ iounmap(np->base);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
/* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
printk(version);
+#ifdef HAVE_NETDEV_POLL
+ printk(KERN_INFO DRV_NAME ": polling (NAPI) enabled\n");
+#else
+ printk(KERN_INFO DRV_NAME ": polling (NAPI) disabled\n");
+#endif
#endif
-#ifndef ADDR_64BITS
+
/* we can do this test only at run-time... sigh */
- if (sizeof(dma_addr_t) == sizeof(u64)) {
- printk("This driver has not been ported to this 64-bit architecture yet\n");
+ if (sizeof(dma_addr_t) != sizeof(netdrv_addr_t)) {
+ printk("This driver has dma_addr_t issues, please send email to maintainer\n");
return -ENODEV;
}
-#endif /* not ADDR_64BITS */
-#ifndef HAS_FIRMWARE
- /* unconditionally disable hw cksums if firmware is not present */
- enable_hw_cksum = 0;
-#endif /* not HAS_FIRMWARE */
+
return pci_module_init (&starfire_driver);
}