I/O access could affect performance in ARM-based system
- Add Linux software VLAN support
- Version LK1.08 (D-Link):
+ Version LK1.08 (Philippe De Muyter phdm@macqel.be):
- Fix bug of custom mac address
(StationAddr register only accept word write)
Version LK1.09a (ICPlus):
- Add the delay time in reading the contents of EEPROM
+ Version LK1.10 (Philippe De Muyter phdm@macqel.be):
+ - Make 'unblock interface after Tx underrun' work
+
*/
#define DRV_NAME "sundance"
-#define DRV_VERSION "1.01+LK1.09a"
-#define DRV_RELDATE "10-Jul-2003"
+#define DRV_VERSION "1.01+LK1.10"
+#define DRV_RELDATE "28-Oct-2005"
/* The user-configurable values.
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
Typical is a 64 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 32;
+static const int multicast_filter_limit = 32;
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1518 effectively disables this feature.
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
+#include <linux/bitops.h>
#include <asm/uaccess.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
MODULE_LICENSE("GPL");
-MODULE_PARM(debug, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
-MODULE_PARM(flowctrl, "i");
+module_param(debug, int, 0);
+module_param(rx_copybreak, int, 0);
+module_param_array(media, charp, NULL, 0);
+module_param(flowctrl, int, 0);
MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
IVb. References
The Sundance ST201 datasheet, preliminary version.
-http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+The Kendin KS8723 datasheet, preliminary version.
+The ICplus IP100 datasheet, preliminary version.
+http://www.scyld.com/expert/100mbps.html
+http://www.scyld.com/expert/NWay.html
IVc. Errata
{0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
{0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
{0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ {0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
{0,}
};
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
struct pci_id_info {
const char *name;
};
-static struct pci_id_info pci_id_tbl[] = {
+static const struct pci_id_info pci_id_tbl[] = {
{"D-Link DFE-550TX FAST Ethernet Adapter"},
{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
{"D-Link DFE-580TX 4 port Server Adapter"},
{"D-Link DFE-530TXS FAST Ethernet Adapter"},
{"D-Link DL10050-based FAST Ethernet Adapter"},
- {"Sundance Technology Alta"},
+ {"IC Plus IP100 Fast Ethernet Adapter"},
+ {"IC Plus IP100A Fast Ethernet Adapter" },
{NULL,}, /* 0 terminated list. */
};
/* This driver was written to use PCI memory space, however x86-oriented
hardware often uses I/O space accesses. */
-#ifdef USE_IO_OPS
-#undef readb
-#undef readw
-#undef readl
-#undef writeb
-#undef writew
-#undef writel
-#define readb inb
-#define readw inw
-#define readl inl
-#define writeb outb
-#define writew outw
-#define writel outl
-#endif
/* Offsets to the device registers.
Unlike software-only systems, device drivers interact with complex hardware.
int mii_preamble_required;
unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */
struct pci_dev *pci_dev;
+ void __iomem *base;
unsigned char pci_rev_id;
};
LinkChange)
static int change_mtu(struct net_device *dev, int new_mtu);
-static int eeprom_read(long ioaddr, int location);
+static int eeprom_read(void __iomem *ioaddr, int location);
static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static int netdev_open(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct net_device *dev);
+static struct ethtool_ops ethtool_ops;
-
+static void sundance_reset(struct net_device *dev, unsigned long reset_cmd)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base + ASICCtrl;
+ int countdown;
+
+ /* ST201 documentation states ASICCtrl is a 32bit register */
+ iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr);
+ /* ST201 documentation states reset can take up to 1 ms */
+ countdown = 10 + 1;
+ while (ioread32 (ioaddr) & (ResetBusy << 16)) {
+ if (--countdown == 0) {
+ printk(KERN_WARNING "%s : reset not completed !!\n", dev->name);
+ break;
+ }
+ udelay(100);
+ }
+}
static int __devinit sundance_probe1 (struct pci_dev *pdev,
const struct pci_device_id *ent)
int chip_idx = ent->driver_data;
int irq;
int i;
- long ioaddr;
+ void __iomem *ioaddr;
u16 mii_ctl;
void *ring_space;
dma_addr_t ring_dma;
+#ifdef USE_IO_OPS
+ int bar = 0;
+#else
+ int bar = 1;
+#endif
+ int phy, phy_idx = 0;
/* when built into the kernel, we only print version if device is found */
if (pci_request_regions(pdev, DRV_NAME))
goto err_out_netdev;
-#ifdef USE_IO_OPS
- ioaddr = pci_resource_start(pdev, 0);
-#else
- ioaddr = pci_resource_start(pdev, 1);
- ioaddr = (long) ioremap (ioaddr, netdev_io_size);
+ ioaddr = pci_iomap(pdev, bar, netdev_io_size);
if (!ioaddr)
goto err_out_res;
-#endif
for (i = 0; i < 3; i++)
((u16 *)dev->dev_addr)[i] =
le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET));
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- dev->base_addr = ioaddr;
+ dev->base_addr = (unsigned long)ioaddr;
dev->irq = irq;
- np = dev->priv;
+ np = netdev_priv(dev);
+ np->base = ioaddr;
np->pci_dev = pdev;
np->chip_id = chip_idx;
np->msg_enable = (1 << debug) - 1;
dev->get_stats = &get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &netdev_ioctl;
+ SET_ETHTOOL_OPS(dev, ðtool_ops);
dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->change_mtu = &change_mtu;
if (i)
goto err_out_unmap_rx;
- printk(KERN_INFO "%s: %s at 0x%lx, ",
+ printk(KERN_INFO "%s: %s at %p, ",
dev->name, pci_id_tbl[chip_idx].name, ioaddr);
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 (1) {
- int phy, phy_idx = 0;
- np->phys[0] = 1; /* Default setting */
- np->mii_preamble_required++;
- for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
- int mii_status = mdio_read(dev, phy, MII_BMSR);
- if (mii_status != 0xffff && mii_status != 0x0000) {
- np->phys[phy_idx++] = phy;
- np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
- if ((mii_status & 0x0040) == 0)
- np->mii_preamble_required++;
- printk(KERN_INFO "%s: MII PHY found at address %d, status "
- "0x%4.4x advertising %4.4x.\n",
- dev->name, phy, mii_status, np->mii_if.advertising);
- }
- }
- np->mii_preamble_required--;
-
- if (phy_idx == 0) {
- printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n",
- dev->name, readl(ioaddr + ASICCtrl));
- goto err_out_unregister;
+ np->phys[0] = 1; /* Default setting */
+ np->mii_preamble_required++;
+ /*
+ * It seems some phys doesn't deal well with address 0 being accessed
+ * first, so leave address zero to the end of the loop (32 & 31).
+ */
+ for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) {
+ int phyx = phy & 0x1f;
+ int mii_status = mdio_read(dev, phyx, MII_BMSR);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ np->phys[phy_idx++] = phyx;
+ np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE);
+ if ((mii_status & 0x0040) == 0)
+ np->mii_preamble_required++;
+ printk(KERN_INFO "%s: MII PHY found at address %d, status "
+ "0x%4.4x advertising %4.4x.\n",
+ dev->name, phyx, mii_status, np->mii_if.advertising);
}
+ }
+ np->mii_preamble_required--;
- np->mii_if.phy_id = np->phys[0];
+ if (phy_idx == 0) {
+ printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n",
+ dev->name, ioread32(ioaddr + ASICCtrl));
+ goto err_out_unregister;
}
+ np->mii_if.phy_id = np->phys[0];
+
/* Parse override configuration */
np->an_enable = 1;
if (card_idx < MAX_UNITS) {
}
/* Fibre PHY? */
- if (readl (ioaddr + ASICCtrl) & 0x80) {
+ if (ioread32 (ioaddr + ASICCtrl) & 0x80) {
/* Default 100Mbps Full */
if (np->an_enable) {
np->speed = 100;
/* Perhaps move the reset here? */
/* Reset the chip to erase previous misconfiguration. */
if (netif_msg_hw(np))
- printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl));
- writew(0x007f, ioaddr + ASICCtrl + 2);
+ printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
+ iowrite16(0x00ff, ioaddr + ASICCtrl + 2);
if (netif_msg_hw(np))
- printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl));
+ printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
card_idx++;
return 0;
pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
err_out_cleardev:
pci_set_drvdata(pdev, NULL);
-#ifndef USE_IO_OPS
- iounmap((void *)ioaddr);
+ pci_iounmap(pdev, ioaddr);
err_out_res:
-#endif
pci_release_regions(pdev);
err_out_netdev:
free_netdev (dev);
return 0;
}
-#define eeprom_delay(ee_addr) readl(ee_addr)
+#define eeprom_delay(ee_addr) ioread32(ee_addr)
/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
-static int __devinit eeprom_read(long ioaddr, int location)
+static int __devinit eeprom_read(void __iomem *ioaddr, int location)
{
int boguscnt = 10000; /* Typical 1900 ticks. */
- writew(0x0200 | (location & 0xff), ioaddr + EECtrl);
+ iowrite16(0x0200 | (location & 0xff), ioaddr + EECtrl);
do {
eeprom_delay(ioaddr + EECtrl);
- if (! (readw(ioaddr + EECtrl) & 0x8000)) {
- return readw(ioaddr + EEData);
+ if (! (ioread16(ioaddr + EECtrl) & 0x8000)) {
+ return ioread16(ioaddr + EEData);
}
} while (--boguscnt > 0);
return 0;
The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
met by back-to-back 33Mhz PCI cycles. */
-#define mdio_delay() readb(mdio_addr)
+#define mdio_delay() ioread8(mdio_addr)
enum mii_reg_bits {
MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
/* Generate the preamble required for initial synchronization and
a few older transceivers. */
-static void mdio_sync(long mdio_addr)
+static void mdio_sync(void __iomem *mdio_addr)
{
int bits = 32;
/* Establish sync by sending at least 32 logic ones. */
while (--bits >= 0) {
- writeb(MDIO_WRITE1, mdio_addr);
+ iowrite8(MDIO_WRITE1, mdio_addr);
mdio_delay();
- writeb(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
+ iowrite8(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
mdio_delay();
}
}
static int mdio_read(struct net_device *dev, int phy_id, int location)
{
- struct netdev_private *np = dev->priv;
- long mdio_addr = dev->base_addr + MIICtrl;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *mdio_addr = np->base + MIICtrl;
int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
int i, retval = 0;
for (i = 15; i >= 0; i--) {
int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
- writeb(dataval, mdio_addr);
+ iowrite8(dataval, mdio_addr);
mdio_delay();
- writeb(dataval | MDIO_ShiftClk, mdio_addr);
+ iowrite8(dataval | MDIO_ShiftClk, mdio_addr);
mdio_delay();
}
/* Read the two transition, 16 data, and wire-idle bits. */
for (i = 19; i > 0; i--) {
- writeb(MDIO_EnbIn, mdio_addr);
+ iowrite8(MDIO_EnbIn, mdio_addr);
mdio_delay();
- retval = (retval << 1) | ((readb(mdio_addr) & MDIO_Data) ? 1 : 0);
- writeb(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+ retval = (retval << 1) | ((ioread8(mdio_addr) & MDIO_Data) ? 1 : 0);
+ iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
mdio_delay();
}
return (retval>>1) & 0xffff;
static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
{
- struct netdev_private *np = dev->priv;
- long mdio_addr = dev->base_addr + MIICtrl;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *mdio_addr = np->base + MIICtrl;
int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
int i;
for (i = 31; i >= 0; i--) {
int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
- writeb(dataval, mdio_addr);
+ iowrite8(dataval, mdio_addr);
mdio_delay();
- writeb(dataval | MDIO_ShiftClk, mdio_addr);
+ iowrite8(dataval | MDIO_ShiftClk, mdio_addr);
mdio_delay();
}
/* Clear out extra bits. */
for (i = 2; i > 0; i--) {
- writeb(MDIO_EnbIn, mdio_addr);
+ iowrite8(MDIO_EnbIn, mdio_addr);
mdio_delay();
- writeb(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+ iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
mdio_delay();
}
return;
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;
/* Do we need to reset the chip??? */
dev->name, dev->irq);
init_ring(dev);
- writel(np->rx_ring_dma, ioaddr + RxListPtr);
+ iowrite32(np->rx_ring_dma, ioaddr + RxListPtr);
/* The Tx list pointer is written as packets are queued. */
/* Initialize other registers. */
__set_mac_addr(dev);
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
- writew(dev->mtu + 18, ioaddr + MaxFrameSize);
+ iowrite16(dev->mtu + 18, ioaddr + MaxFrameSize);
#else
- writew(dev->mtu + 14, ioaddr + MaxFrameSize);
+ iowrite16(dev->mtu + 14, ioaddr + MaxFrameSize);
#endif
if (dev->mtu > 2047)
- writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
+ iowrite32(ioread32(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
/* Configure the PCI bus bursts and FIFO thresholds. */
if (dev->if_port == 0)
dev->if_port = np->default_port;
- np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&np->mcastlock);
set_rx_mode(dev);
- writew(0, ioaddr + IntrEnable);
- writew(0, ioaddr + DownCounter);
+ iowrite16(0, ioaddr + IntrEnable);
+ iowrite16(0, ioaddr + DownCounter);
/* Set the chip to poll every N*320nsec. */
- writeb(100, ioaddr + RxDMAPollPeriod);
- writeb(127, ioaddr + TxDMAPollPeriod);
+ iowrite8(100, ioaddr + RxDMAPollPeriod);
+ iowrite8(127, ioaddr + TxDMAPollPeriod);
/* Fix DFE-580TX packet drop issue */
if (np->pci_rev_id >= 0x14)
- writeb(0x01, ioaddr + DebugCtrl1);
+ iowrite8(0x01, ioaddr + DebugCtrl1);
netif_start_queue(dev);
- writew (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
+ iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
if (netif_msg_ifup(np))
printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
"MAC Control %x, %4.4x %4.4x.\n",
- dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus),
- readl(ioaddr + MACCtrl0),
- readw(ioaddr + MACCtrl1), readw(ioaddr + MACCtrl0));
+ dev->name, ioread32(ioaddr + RxStatus), ioread8(ioaddr + TxStatus),
+ ioread32(ioaddr + MACCtrl0),
+ ioread16(ioaddr + MACCtrl1), ioread16(ioaddr + MACCtrl0));
/* Set the timer to check for link beat. */
init_timer(&np->timer);
add_timer(&np->timer);
/* Enable interrupts by setting the interrupt mask. */
- writew(DEFAULT_INTR, ioaddr + IntrEnable);
+ iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
return 0;
}
static void check_duplex(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 mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
int negotiated = mii_lpa & np->mii_if.advertising;
int duplex;
/* Force media */
if (!np->an_enable || mii_lpa == 0xffff) {
if (np->mii_if.full_duplex)
- writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex,
+ iowrite16 (ioread16 (ioaddr + MACCtrl0) | EnbFullDuplex,
ioaddr + MACCtrl0);
return;
}
printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
"negotiated capability %4.4x.\n", dev->name,
duplex ? "full" : "half", np->phys[0], negotiated);
- writew(readw(ioaddr + MACCtrl0) | duplex ? 0x20 : 0, ioaddr + MACCtrl0);
+ iowrite16(ioread16(ioaddr + MACCtrl0) | duplex ? 0x20 : 0, ioaddr + MACCtrl0);
}
}
static void netdev_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
- struct netdev_private *np = dev->priv;
- long ioaddr = dev->base_addr;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
int next_tick = 10*HZ;
if (netif_msg_timer(np)) {
printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, "
"Tx %x Rx %x.\n",
- dev->name, readw(ioaddr + IntrEnable),
- readb(ioaddr + TxStatus), readl(ioaddr + RxStatus));
+ dev->name, ioread16(ioaddr + IntrEnable),
+ ioread8(ioaddr + TxStatus), ioread32(ioaddr + RxStatus));
}
check_duplex(dev);
np->timer.expires = jiffies + next_tick;
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;
unsigned long flag;
netif_stop_queue(dev);
tasklet_disable(&np->tx_tasklet);
- writew(0, ioaddr + IntrEnable);
+ iowrite16(0, ioaddr + IntrEnable);
printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
"TxFrameId %2.2x,"
- " resetting...\n", dev->name, readb(ioaddr + TxStatus),
- readb(ioaddr + TxFrameId));
+ " resetting...\n", dev->name, ioread8(ioaddr + TxStatus),
+ ioread8(ioaddr + TxFrameId));
{
int i;
le32_to_cpu(np->tx_ring[i].frag[0].length));
}
printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
- readl(dev->base_addr + TxListPtr),
+ ioread32(np->base + TxListPtr),
netif_queue_stopped(dev));
printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
np->cur_tx, np->cur_tx % TX_RING_SIZE,
if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
netif_wake_queue(dev);
}
- writew(DEFAULT_INTR, ioaddr + IntrEnable);
+ iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
tasklet_enable(&np->tx_tasklet);
}
/* 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 = 0;
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
np->rx_ring[i].frag[0].addr = cpu_to_le32(
- pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz,
+ pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz,
PCI_DMA_FROMDEVICE));
np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
}
static void tx_poll (unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
unsigned head = np->cur_task % TX_RING_SIZE;
struct netdev_desc *txdesc =
&np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
/* Indicate the latest descriptor of tx ring */
txdesc->status |= cpu_to_le32(DescIntrOnTx);
- if (readl (dev->base_addr + TxListPtr) == 0)
- writel (np->tx_ring_dma + head * sizeof(struct netdev_desc),
- dev->base_addr + TxListPtr);
+ if (ioread32 (np->base + TxListPtr) == 0)
+ iowrite32 (np->tx_ring_dma + head * sizeof(struct netdev_desc),
+ np->base + TxListPtr);
return;
}
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);
struct netdev_desc *txdesc;
unsigned entry;
static int
reset_tx (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;
struct sk_buff *skb;
int i;
int irq = in_interrupt();
/* Reset tx logic, TxListPtr will be cleaned */
- writew (TxDisable, ioaddr + MACCtrl1);
- writew (TxReset | DMAReset | FIFOReset | NetworkReset,
+ iowrite16 (TxDisable, ioaddr + MACCtrl1);
+ iowrite16 (TxReset | DMAReset | FIFOReset | NetworkReset,
ioaddr + ASICCtrl + 2);
for (i=50; i > 0; i--) {
- if ((readw(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+ if ((ioread16(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
break;
mdelay(1);
}
}
np->cur_tx = np->dirty_tx = 0;
np->cur_task = 0;
- writew (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
+ iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
return 0;
}
static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
{
struct net_device *dev = (struct net_device *)dev_instance;
- struct netdev_private *np;
- long ioaddr;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
int hw_frame_id;
int tx_cnt;
int tx_status;
int handled = 0;
- ioaddr = dev->base_addr;
- np = dev->priv;
do {
- int intr_status = readw(ioaddr + IntrStatus);
- writew(intr_status, ioaddr + IntrStatus);
+ int intr_status = ioread16(ioaddr + IntrStatus);
+ iowrite16(intr_status, ioaddr + IntrStatus);
if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
handled = 1;
if (intr_status & (IntrRxDMADone)) {
- writew(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
+ iowrite16(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
ioaddr + IntrEnable);
if (np->budget < 0)
np->budget = RX_BUDGET;
tasklet_schedule(&np->rx_tasklet);
}
if (intr_status & (IntrTxDone | IntrDrvRqst)) {
- tx_status = readw (ioaddr + TxStatus);
+ tx_status = ioread16 (ioaddr + TxStatus);
for (tx_cnt=32; tx_status & 0x80; --tx_cnt) {
if (netif_msg_tx_done(np))
printk
("%s: Transmit status is %2.2x.\n",
dev->name, tx_status);
if (tx_status & 0x1e) {
+ if (netif_msg_tx_err(np))
+ printk("%s: Transmit error status %4.4x.\n",
+ dev->name, tx_status);
np->stats.tx_errors++;
if (tx_status & 0x10)
np->stats.tx_fifo_errors++;
if (tx_status & 0x08)
np->stats.collisions++;
+ if (tx_status & 0x04)
+ np->stats.tx_fifo_errors++;
if (tx_status & 0x02)
np->stats.tx_window_errors++;
- /* This reset has not been verified!. */
- if (tx_status & 0x10) { /* Reset the Tx. */
- np->stats.tx_fifo_errors++;
- spin_lock(&np->lock);
- reset_tx(dev);
- spin_unlock(&np->lock);
+ /*
+ ** This reset has been verified on
+ ** DFE-580TX boards ! phdm@macqel.be.
+ */
+ if (tx_status & 0x10) { /* TxUnderrun */
+ unsigned short txthreshold;
+
+ txthreshold = ioread16 (ioaddr + TxStartThresh);
+ /* Restart Tx FIFO and transmitter */
+ sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16);
+ iowrite16 (txthreshold, ioaddr + TxStartThresh);
+ /* No need to reset the Tx pointer here */
}
- if (tx_status & 0x1e) /* Restart the Tx. */
- writew (TxEnable,
- ioaddr + MACCtrl1);
+ /* Restart the Tx. */
+ iowrite16 (TxEnable, ioaddr + MACCtrl1);
}
/* Yup, this is a documentation bug. It cost me *hours*. */
- writew (0, ioaddr + TxStatus);
- tx_status = readw (ioaddr + TxStatus);
- if (tx_cnt < 0)
+ iowrite16 (0, ioaddr + TxStatus);
+ if (tx_cnt < 0) {
+ iowrite32(5000, ioaddr + DownCounter);
break;
+ }
+ tx_status = ioread16 (ioaddr + TxStatus);
}
hw_frame_id = (tx_status >> 8) & 0xff;
} else {
- hw_frame_id = readb(ioaddr + TxFrameId);
+ hw_frame_id = ioread8(ioaddr + TxFrameId);
}
if (np->pci_rev_id >= 0x14) {
} while (0);
if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
- dev->name, readw(ioaddr + IntrStatus));
- writel(5000, ioaddr + DownCounter);
+ dev->name, ioread16(ioaddr + IntrStatus));
return IRQ_RETVAL(handled);
}
static void rx_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
int entry = np->cur_rx % RX_RING_SIZE;
int boguscnt = np->budget;
- long ioaddr = dev->base_addr;
+ void __iomem *ioaddr = np->base;
int received = 0;
/* If EOP is set on the next entry, it's a new packet. Send it up. */
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0);
pci_dma_sync_single_for_device(np->pci_dev,
desc->frag[0].addr,
np->rx_buf_sz,
np->cur_rx = entry;
refill_rx (dev);
np->budget -= received;
- writew(DEFAULT_INTR, ioaddr + IntrEnable);
+ iowrite16(DEFAULT_INTR, ioaddr + IntrEnable);
return;
not_done:
static void refill_rx (struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
int entry;
int cnt = 0;
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
np->rx_ring[entry].frag[0].addr = cpu_to_le32(
- pci_map_single(np->pci_dev, skb->tail,
+ pci_map_single(np->pci_dev, skb->data,
np->rx_buf_sz, PCI_DMA_FROMDEVICE));
}
/* Perhaps we need not reset this field. */
}
static void netdev_error(struct net_device *dev, int intr_status)
{
- long ioaddr = dev->base_addr;
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->base;
u16 mii_ctl, mii_advertise, mii_lpa;
int speed;
}
check_duplex (dev);
if (np->flowctrl && np->mii_if.full_duplex) {
- writew(readw(ioaddr + MulticastFilter1+2) | 0x0200,
+ iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200,
ioaddr + MulticastFilter1+2);
- writew(readw(ioaddr + MACCtrl0) | EnbFlowCtrl,
+ iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl,
ioaddr + MACCtrl0);
}
}
static struct net_device_stats *get_stats(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;
/* We should lock this segment of code for SMP eventually, although
the vulnerability window is very small and statistics are
non-critical. */
/* The chip only need report frame silently dropped. */
- np->stats.rx_missed_errors += readb(ioaddr + RxMissed);
- np->stats.tx_packets += readw(ioaddr + TxFramesOK);
- np->stats.rx_packets += readw(ioaddr + RxFramesOK);
- np->stats.collisions += readb(ioaddr + StatsLateColl);
- np->stats.collisions += readb(ioaddr + StatsMultiColl);
- np->stats.collisions += readb(ioaddr + StatsOneColl);
- np->stats.tx_carrier_errors += readb(ioaddr + StatsCarrierError);
- readb(ioaddr + StatsTxDefer);
+ np->stats.rx_missed_errors += ioread8(ioaddr + RxMissed);
+ np->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
+ np->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
+ np->stats.collisions += ioread8(ioaddr + StatsLateColl);
+ np->stats.collisions += ioread8(ioaddr + StatsMultiColl);
+ np->stats.collisions += ioread8(ioaddr + StatsOneColl);
+ np->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
+ ioread8(ioaddr + StatsTxDefer);
for (i = StatsTxDefer; i <= StatsMcastRx; i++)
- readb(ioaddr + i);
- np->stats.tx_bytes += readw(ioaddr + TxOctetsLow);
- np->stats.tx_bytes += readw(ioaddr + TxOctetsHigh) << 16;
- np->stats.rx_bytes += readw(ioaddr + RxOctetsLow);
- np->stats.rx_bytes += readw(ioaddr + RxOctetsHigh) << 16;
+ ioread8(ioaddr + i);
+ np->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
+ np->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
+ np->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
+ np->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
return &np->stats;
}
static void set_rx_mode(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;
u16 mc_filter[4]; /* Multicast hash filter */
u32 rx_mode;
int i;
}
rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys;
} else {
- writeb(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode);
+ iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode);
return;
}
if (np->mii_if.full_duplex && np->flowctrl)
mc_filter[3] |= 0x0200;
for (i = 0; i < 4; i++)
- writew(mc_filter[i], ioaddr + MulticastFilter0 + i*2);
- writeb(rx_mode, ioaddr + RxMode);
+ iowrite16(mc_filter[i], ioaddr + MulticastFilter0 + i*2);
+ iowrite8(rx_mode, ioaddr + RxMode);
}
static int __set_mac_addr(struct net_device *dev)
{
+ struct netdev_private *np = netdev_priv(dev);
u16 addr16;
addr16 = (dev->dev_addr[0] | (dev->dev_addr[1] << 8));
- writew(addr16, dev->base_addr + StationAddr);
+ iowrite16(addr16, np->base + StationAddr);
addr16 = (dev->dev_addr[2] | (dev->dev_addr[3] << 8));
- writew(addr16, dev->base_addr + StationAddr+2);
+ iowrite16(addr16, np->base + StationAddr+2);
addr16 = (dev->dev_addr[4] | (dev->dev_addr[5] << 8));
- writew(addr16, dev->base_addr + StationAddr+4);
+ iowrite16(addr16, np->base + StationAddr+4);
return 0;
}
-
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static int check_if_running(struct net_device *dev)
{
- struct netdev_private *np = dev->priv;
- u32 ethcmd;
-
- if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
- return -EFAULT;
-
- switch (ethcmd) {
- /* get constant driver settings/info */
- case ETHTOOL_GDRVINFO: {
- struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
- strcpy(info.driver, DRV_NAME);
- strcpy(info.version, DRV_VERSION);
- strcpy(info.bus_info, pci_name(np->pci_dev));
- memset(&info.fw_version, 0, sizeof(info.fw_version));
- if (copy_to_user(useraddr, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
+ if (!netif_running(dev))
+ return -EINVAL;
+ return 0;
+}
- /* get media 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 media 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);
- return r;
- }
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ 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));
+}
- /* restart autonegotiation */
- case ETHTOOL_NWAY_RST: {
- return mii_nway_restart(&np->mii_if);
- }
+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 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 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);
+ return res;
+}
- /* get message-level */
- case ETHTOOL_GMSGLVL: {
- struct ethtool_value edata = {ETHTOOL_GMSGLVL};
- edata.data = np->msg_enable;
- 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;
- np->msg_enable = edata.data;
- return 0;
- }
+static int nway_reset(struct net_device *dev)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ return mii_nway_restart(&np->mii_if);
+}
- default:
- return -EOPNOTSUPP;
+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)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ return np->msg_enable;
}
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ np->msg_enable = 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,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+};
+
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);
+ void __iomem *ioaddr = np->base;
int rc;
int i;
- long ioaddr = dev->base_addr;
if (!netif_running(dev))
return -EINVAL;
- if (cmd == SIOCETHTOOL)
- rc = netdev_ethtool_ioctl(dev, rq->ifr_data);
-
- else {
- spin_lock_irq(&np->lock);
- rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL);
- spin_unlock_irq(&np->lock);
- }
+ spin_lock_irq(&np->lock);
+ rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL);
+ spin_unlock_irq(&np->lock);
switch (cmd) {
case SIOCDEVPRIVATE:
for (i=0; i<TX_RING_SIZE; i++) {
le32_to_cpu(np->tx_ring[i].frag[0].length));
}
printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
- readl(dev->base_addr + TxListPtr),
+ ioread32(np->base + TxListPtr),
netif_queue_stopped(dev));
printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
np->cur_tx, np->cur_tx % TX_RING_SIZE,
np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
- printk(KERN_DEBUG "TxStatus=%04x\n", readw(ioaddr + TxStatus));
+ printk(KERN_DEBUG "TxStatus=%04x\n", ioread16(ioaddr + TxStatus));
return 0;
}
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;
struct sk_buff *skb;
int i;
if (netif_msg_ifdown(np)) {
printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x "
"Rx %4.4x Int %2.2x.\n",
- dev->name, readb(ioaddr + TxStatus),
- readl(ioaddr + RxStatus), readw(ioaddr + IntrStatus));
+ dev->name, ioread8(ioaddr + TxStatus),
+ ioread32(ioaddr + RxStatus), ioread16(ioaddr + IntrStatus));
printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
}
/* Disable interrupts by clearing the interrupt mask. */
- writew(0x0000, ioaddr + IntrEnable);
+ iowrite16(0x0000, ioaddr + IntrEnable);
/* Stop the chip's Tx and Rx processes. */
- writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
+ iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
/* Wait and kill tasklet */
tasklet_kill(&np->rx_tasklet);
struct net_device *dev = pci_get_drvdata(pdev);
if (dev) {
- struct netdev_private *np = dev->priv;
+ struct netdev_private *np = netdev_priv(dev);
unregister_netdev(dev);
pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,
np->rx_ring_dma);
pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring,
np->tx_ring_dma);
+ pci_iounmap(pdev, np->base);
pci_release_regions(pdev);
-#ifndef USE_IO_OPS
- iounmap((char *)(dev->base_addr));
-#endif
free_netdev(dev);
pci_set_drvdata(pdev, NULL);
}