* cb_to_use is the next CB to use for queuing a command; cb_to_clean
* is the next CB to check for completion; cb_to_send is the first
* CB to start on in case of a previous failure to resume. CB clean
- * up happens in interrupt context in response to a CU interrupt, or
- * in dev->poll in the case where NAPI is enabled. cbs_avail keeps
- * track of number of free CB resources available.
+ * up happens in interrupt context in response to a CU interrupt.
+ * cbs_avail keeps track of number of free CB resources available.
*
* Hardware padding of short packets to minimum packet size is
* enabled. 82557 pads with 7Eh, while the later controllers pad
* replacement RFDs cannot be allocated, or the RU goes non-active,
* the RU must be restarted. Frame arrival generates an interrupt,
* and Rx indication and re-allocation happen in the same context,
- * therefore no locking is required. If NAPI is enabled, this work
- * happens in dev->poll. A software-generated interrupt is gen-
- * erated from the watchdog to recover from a failed allocation
+ * therefore no locking is required. A software-generated interrupt
+ * is generated from the watchdog to recover from a failed allocation
* senario where all Rx resources have been indicated and none re-
* placed.
*
* supported. Tx Scatter/Gather is not supported. Jumbo Frames is
* not supported (hardware limitation).
*
- * NAPI support is enabled with CONFIG_E100_NAPI.
- *
* MagicPacket(tm) WoL support is enabled/disabled via ethtool.
*
* Thanks to JC (jchapman@katalix.com) for helping with
#define DRV_NAME "e100"
-#define DRV_VERSION "3.0.17"
+#define DRV_EXT "-NAPI"
+#define DRV_VERSION "3.4.8-k2"DRV_EXT
#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation"
+#define DRV_COPYRIGHT "Copyright(c) 1999-2005 Intel Corporation"
#define PFX DRV_NAME ": "
#define E100_WATCHDOG_PERIOD (2 * HZ)
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
static int debug = 3;
module_param(debug, int, 0);
INTEL_8255X_ETHERNET_DEVICE(0x1053, 5),
INTEL_8255X_ETHERNET_DEVICE(0x1054, 5),
INTEL_8255X_ETHERNET_DEVICE(0x1055, 5),
+ INTEL_8255X_ETHERNET_DEVICE(0x1056, 5),
+ INTEL_8255X_ETHERNET_DEVICE(0x1057, 5),
+ INTEL_8255X_ETHERNET_DEVICE(0x1059, 0),
INTEL_8255X_ETHERNET_DEVICE(0x1064, 6),
INTEL_8255X_ETHERNET_DEVICE(0x1065, 6),
INTEL_8255X_ETHERNET_DEVICE(0x1066, 6),
INTEL_8255X_ETHERNET_DEVICE(0x1069, 6),
INTEL_8255X_ETHERNET_DEVICE(0x106A, 6),
INTEL_8255X_ETHERNET_DEVICE(0x106B, 6),
- INTEL_8255X_ETHERNET_DEVICE(0x1059, 0),
+ INTEL_8255X_ETHERNET_DEVICE(0x1091, 7),
+ INTEL_8255X_ETHERNET_DEVICE(0x1092, 7),
+ INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
+ INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
+ INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
INTEL_8255X_ETHERNET_DEVICE(0x2459, 2),
INTEL_8255X_ETHERNET_DEVICE(0x245D, 2),
+ INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7),
{ 0, }
};
MODULE_DEVICE_TABLE(pci, e100_id_table);
phy_nsc_tx = 0x5C002000,
phy_82562_et = 0x033002A8,
phy_82562_em = 0x032002A8,
+ phy_82562_ek = 0x031002A8,
phy_82562_eh = 0x017002A8,
phy_unknown = 0xFFFFFFFF,
};
rus_mask = 0x3C,
};
+enum ru_state {
+ RU_SUSPENDED = 0,
+ RU_RUNNING = 1,
+ RU_UNINITIALIZED = -1,
+};
+
enum scb_stat_ack {
stat_ack_not_ours = 0x00,
stat_ack_sw_gen = 0x04,
};
enum eeprom_offsets {
+ eeprom_cnfg_mdix = 0x03,
eeprom_id = 0x0A,
eeprom_config_asf = 0x0D,
eeprom_smbus_addr = 0x90,
};
+enum eeprom_cnfg_mdix {
+ eeprom_mdix_enabled = 0x0080,
+};
+
enum eeprom_id {
eeprom_id_wol = 0x0020,
};
};
enum cb_command {
+ cb_nop = 0x0000,
cb_iaaddr = 0x0001,
cb_config = 0x0002,
cb_multi = 0x0003,
cb_tx = 0x0004,
+ cb_ucode = 0x0005,
cb_dump = 0x0006,
cb_tx_sf = 0x0008,
cb_cid = 0x1f00,
};
/* Important: keep total struct u32-aligned */
+#define UCODE_SIZE 134
struct cb {
u16 status;
u16 command;
u32 link;
union {
u8 iaaddr[ETH_ALEN];
+ u32 ucode[UCODE_SIZE];
struct config config;
struct multi multi;
struct {
struct rx *rx_to_use;
struct rx *rx_to_clean;
struct rfd blank_rfd;
- int ru_running;
+ enum ru_state ru_running;
spinlock_t cb_lock ____cacheline_aligned;
spinlock_t cmd_lock;
- struct csr *csr;
+ struct csr __iomem *csr;
enum scb_cmd_lo cuc_cmd;
unsigned int cbs_avail;
struct cb *cbs;
struct timer_list watchdog;
struct timer_list blink_timer;
struct mii_if_info mii;
+ struct work_struct tx_timeout_task;
enum loopback loopback;
struct mem *mem;
u32 rx_fc_pause;
u32 rx_fc_unsupported;
u32 rx_tco_frames;
+ u32 rx_over_length_errors;
u8 rev_id;
u16 leds;
u16 eeprom_wc;
u16 eeprom[256];
- u32 pm_state[16];
};
static inline void e100_write_flush(struct nic *nic)
static inline void e100_enable_irq(struct nic *nic)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&nic->cmd_lock, flags);
writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
+ spin_unlock_irqrestore(&nic->cmd_lock, flags);
e100_write_flush(nic);
}
static inline void e100_disable_irq(struct nic *nic)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&nic->cmd_lock, flags);
writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
+ spin_unlock_irqrestore(&nic->cmd_lock, flags);
e100_write_flush(nic);
}
writel(software_reset, &nic->csr->port);
e100_write_flush(nic); udelay(20);
- /* TCO workaround - 82559 and greater */
- if(nic->mac >= mac_82559_D101M) {
- /* Issue a redundant CU load base without setting
- * general pointer, and without waiting for scb to
- * clear. This gets us into post-driver. Finally,
- * wait 20 msec for reset to take effect. */
- writeb(cuc_load_base, &nic->csr->scb.cmd_lo);
- mdelay(20);
- }
-
/* Mask off our interrupt line - it's unmasked after reset */
e100_disable_irq(nic);
}
writel(selftest | dma_addr, &nic->csr->port);
e100_write_flush(nic);
/* Wait 10 msec for self-test to complete */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 100 + 1);
+ msleep(10);
/* Interrupts are enabled after self-test */
e100_disable_irq(nic);
/* Three cmds: write/erase enable, write data, write/erase disable */
cmd_addr_data[0] = op_ewen << (addr_len - 2);
- cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) | data;
+ cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) |
+ cpu_to_le16(data);
cmd_addr_data[2] = op_ewds << (addr_len - 2);
/* Bit-bang cmds to write word to eeprom */
e100_write_flush(nic); udelay(4);
}
/* Wait 10 msec for cmd to complete */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 100 + 1);
+ msleep(10);
/* Chip deselect */
writeb(0, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
}
-
};
/* General technique stolen from the eepro100 driver - very clever */
writeb(0, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
- return data;
+ return le16_to_cpu(data);
};
/* Load entire EEPROM image into driver cache and validate checksum */
for(addr = 0; addr < nic->eeprom_wc; addr++) {
nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr);
if(addr < nic->eeprom_wc - 1)
- checksum += nic->eeprom[addr];
+ checksum += cpu_to_le16(nic->eeprom[addr]);
}
/* The checksum, stored in the last word, is calculated such that
* the sum of words should be 0xBABA */
- checksum = 0xBABA - checksum;
+ checksum = le16_to_cpu(0xBABA - checksum);
if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
return -EAGAIN;
/* The checksum, stored in the last word, is calculated such that
* the sum of words should be 0xBABA */
for(addr = 0; addr < nic->eeprom_wc - 1; addr++)
- checksum += nic->eeprom[addr];
- nic->eeprom[nic->eeprom_wc - 1] = 0xBABA - checksum;
- e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, 0xBABA - checksum);
+ checksum += cpu_to_le16(nic->eeprom[addr]);
+ nic->eeprom[nic->eeprom_wc - 1] = le16_to_cpu(0xBABA - checksum);
+ e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1,
+ nic->eeprom[nic->eeprom_wc - 1]);
return 0;
}
-#define E100_WAIT_SCB_TIMEOUT 40
+#define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */
static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
{
unsigned long flags;
cb->prev->command &= cpu_to_le16(~cb_s);
while(nic->cb_to_send != nic->cb_to_use) {
- if(unlikely((err = e100_exec_cmd(nic, nic->cuc_cmd,
- nic->cb_to_send->dma_addr)))) {
+ if(unlikely(e100_exec_cmd(nic, nic->cuc_cmd,
+ nic->cb_to_send->dma_addr))) {
/* Ok, here's where things get sticky. It's
* possible that we can't schedule the command
* because the controller is too busy, so
* let's just queue the command and try again
* when another command is scheduled. */
+ if(err == -ENOSPC) {
+ //request a reset
+ schedule_work(&nic->tx_timeout_task);
+ }
break;
} else {
nic->cuc_cmd = cuc_resume;
static int mdio_read(struct net_device *netdev, int addr, int reg)
{
- return mdio_ctrl(netdev->priv, addr, mdi_read, reg, 0);
+ return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0);
}
static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
{
- mdio_ctrl(netdev->priv, addr, mdi_write, reg, data);
+ mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data);
}
static void e100_get_defaults(struct nic *nic)
{
- struct param_range rfds = { .min = 64, .max = 256, .count = 64 };
+ struct param_range rfds = { .min = 16, .max = 256, .count = 64 };
struct param_range cbs = { .min = 64, .max = 256, .count = 64 };
pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
/* Quadwords to DMA into FIFO before starting frame transmit */
nic->tx_threshold = 0xE0;
- nic->tx_command = cpu_to_le16(cb_tx | cb_i | cb_tx_sf |
- ((nic->mac >= mac_82558_D101_A4) ? cb_cid : 0));
+ /* no interrupt for every tx completion, delay = 256us if not 557*/
+ nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf |
+ ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
/* Template for a freshly allocated RFD */
nic->blank_rfd.command = cpu_to_le16(cb_el);
if(nic->flags & multicast_all)
config->multicast_all = 0x1; /* 1=accept, 0=no */
- if(!(nic->flags & wol_magic))
+ /* disable WoL when up */
+ if(netif_running(nic->netdev) || !(nic->flags & wol_magic))
config->magic_packet_disable = 0x1; /* 1=off, 0=on */
if(nic->mac >= mac_82558_D101_A4) {
c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
}
+static void e100_load_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+ int i;
+ static const u32 ucode[UCODE_SIZE] = {
+ /* NFS packets are misinterpreted as TCO packets and
+ * incorrectly routed to the BMC over SMBus. This
+ * microcode patch checks the fragmented IP bit in the
+ * NFS/UDP header to distinguish between NFS and TCO. */
+ 0x0EF70E36, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF, 0x1FFF1FFF,
+ 0x1FFF1FFF, 0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000,
+ 0x00906EFD, 0x00900EFD, 0x00E00EF8,
+ };
+
+ if(nic->mac == mac_82551_F || nic->mac == mac_82551_10) {
+ for(i = 0; i < UCODE_SIZE; i++)
+ cb->u.ucode[i] = cpu_to_le32(ucode[i]);
+ cb->command = cpu_to_le16(cb_ucode);
+ } else
+ cb->command = cpu_to_le16(cb_nop);
+}
+
static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
struct sk_buff *skb)
{
mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
}
- if(nic->mac >= mac_82550_D102)
+ if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
+ (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
+ (nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)))
/* enable/disable MDI/MDI-X auto-switching */
mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
return err;
if((err = e100_exec_cmd(nic, ruc_load_base, 0)))
return err;
+ if((err = e100_exec_cb(nic, NULL, e100_load_ucode)))
+ return err;
if((err = e100_exec_cb(nic, NULL, e100_configure)))
return err;
if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr)))
static void e100_set_multicast_list(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
netdev->mc_count, netdev->flags);
ns->tx_errors += le32_to_cpu(s->tx_max_collisions) +
le32_to_cpu(s->tx_lost_crs);
ns->rx_dropped += le32_to_cpu(s->rx_resource_errors);
- ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors);
+ ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) +
+ nic->rx_over_length_errors;
ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors);
ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors);
+ ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors);
ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors);
ns->rx_errors += le32_to_cpu(s->rx_crc_errors) +
le32_to_cpu(s->rx_alignment_errors) +
}
}
- e100_exec_cmd(nic, cuc_dump_reset, 0);
+
+ if(e100_exec_cmd(nic, cuc_dump_reset, 0))
+ DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");
}
static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
mii_check_link(&nic->mii);
/* Software generated interrupt to recover from (rare) Rx
- * allocation failure */
- writeb(irq_sw_gen, &nic->csr->scb.cmd_hi);
+ * allocation failure.
+ * Unfortunately have to use a spinlock to not re-enable interrupts
+ * accidentally, due to hardware that shares a register between the
+ * interrupt mask bit and the SW Interrupt generation bit */
+ spin_lock_irq(&nic->cmd_lock);
+ writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
+ spin_unlock_irq(&nic->cmd_lock);
e100_write_flush(nic);
e100_update_stats(nic);
struct sk_buff *skb)
{
cb->command = nic->tx_command;
+ /* interrupt every 16 packets regardless of delay */
+ if((nic->cbs_avail & ~15) == nic->cbs_avail) cb->command |= cb_i;
cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);
cb->u.tcb.tcb_byte_count = 0;
cb->u.tcb.threshold = nic->tx_threshold;
cb->u.tcb.tbd_count = 1;
cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,
skb->data, skb->len, PCI_DMA_TODEVICE));
+ // check for mapping failure?
cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
}
static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
int err;
if(nic->flags & ich_10h_workaround) {
/* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.
Issue a NOP command followed by a 1us delay before
issuing the Tx command. */
- e100_exec_cmd(nic, cuc_nop, 0);
+ if(e100_exec_cmd(nic, cuc_nop, 0))
+ DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");
udelay(1);
}
switch(err) {
case -ENOSPC:
/* We queued the skb, but now we're out of space. */
+ DPRINTK(TX_ERR, DEBUG, "No space for CB\n");
netif_stop_queue(netdev);
break;
case -ENOMEM:
static void e100_clean_cbs(struct nic *nic)
{
if(nic->cbs) {
- while(nic->cb_to_clean != nic->cb_to_use) {
+ while(nic->cbs_avail != nic->params.cbs.count) {
struct cb *cb = nic->cb_to_clean;
if(cb->skb) {
pci_unmap_single(nic->pdev,
dev_kfree_skb(cb->skb);
}
nic->cb_to_clean = nic->cb_to_clean->next;
+ nic->cbs_avail++;
}
- nic->cbs_avail = nic->params.cbs.count;
pci_free_consistent(nic->pdev,
sizeof(struct cb) * nic->params.cbs.count,
nic->cbs, nic->cbs_dma_addr);
return 0;
}
-static inline void e100_start_receiver(struct nic *nic)
+static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
{
+ if(!nic->rxs) return;
+ if(RU_SUSPENDED != nic->ru_running) return;
+
+ /* handle init time starts */
+ if(!rx) rx = nic->rxs;
+
/* (Re)start RU if suspended or idle and RFA is non-NULL */
- if(!nic->ru_running && nic->rx_to_clean->skb) {
- e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
- nic->ru_running = 1;
+ if(rx->skb) {
+ e100_exec_cmd(nic, ruc_start, rx->dma_addr);
+ nic->ru_running = RU_RUNNING;
}
}
#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
{
- unsigned int rx_offset = 2; /* u32 align protocol headers */
-
- if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + rx_offset)))
+ if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN)))
return -ENOMEM;
- /* Align, init, and map the RFA. */
+ /* Align, init, and map the RFD. */
rx->skb->dev = nic->netdev;
- skb_reserve(rx->skb, rx_offset);
+ skb_reserve(rx->skb, NET_IP_ALIGN);
memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));
rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
- RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+ RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
+
+ if(pci_dma_mapping_error(rx->dma_addr)) {
+ dev_kfree_skb_any(rx->skb);
+ rx->skb = 0;
+ rx->dma_addr = 0;
+ return -ENOMEM;
+ }
/* Link the RFD to end of RFA by linking previous RFD to
* this one, and clearing EL bit of previous. */
wmb();
prev_rfd->command &= ~cpu_to_le16(cb_el);
pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
- sizeof(struct rfd), PCI_DMA_TODEVICE);
+ sizeof(struct rfd), PCI_DMA_TODEVICE);
}
return 0;
/* Need to sync before taking a peek at cb_complete bit */
pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr,
- sizeof(struct rfd), PCI_DMA_FROMDEVICE);
+ sizeof(struct rfd), PCI_DMA_FROMDEVICE);
rfd_status = le16_to_cpu(rfd->status);
DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
/* If data isn't ready, nothing to indicate */
if(unlikely(!(rfd_status & cb_complete)))
- return -EAGAIN;
+ return -ENODATA;
/* Get actual data size */
actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
/* Get data */
pci_unmap_single(nic->pdev, rx->dma_addr,
- RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+ RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+
+ /* this allows for a fast restart without re-enabling interrupts */
+ if(le16_to_cpu(rfd->command) & cb_el)
+ nic->ru_running = RU_SUSPENDED;
/* Pull off the RFD and put the actual data (minus eth hdr) */
skb_reserve(skb, sizeof(struct rfd));
dev_kfree_skb_any(skb);
} else if(actual_size > nic->netdev->mtu + VLAN_ETH_HLEN) {
/* Don't indicate oversized frames */
- nic->net_stats.rx_over_errors++;
+ nic->rx_over_length_errors++;
nic->net_stats.rx_dropped++;
dev_kfree_skb_any(skb);
} else {
nic->net_stats.rx_packets++;
nic->net_stats.rx_bytes += actual_size;
nic->netdev->last_rx = jiffies;
-#ifdef CONFIG_E100_NAPI
netif_receive_skb(skb);
-#else
- netif_rx(skb);
-#endif
if(work_done)
(*work_done)++;
}
unsigned int work_to_do)
{
struct rx *rx;
+ int restart_required = 0;
+ struct rx *rx_to_start = NULL;
+
+ /* are we already rnr? then pay attention!!! this ensures that
+ * the state machine progression never allows a start with a
+ * partially cleaned list, avoiding a race between hardware
+ * and rx_to_clean when in NAPI mode */
+ if(RU_SUSPENDED == nic->ru_running)
+ restart_required = 1;
/* Indicate newly arrived packets */
for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
- if(e100_rx_indicate(nic, rx, work_done, work_to_do))
+ int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
+ if(-EAGAIN == err) {
+ /* hit quota so have more work to do, restart once
+ * cleanup is complete */
+ restart_required = 0;
+ break;
+ } else if(-ENODATA == err)
break; /* No more to clean */
}
+ /* save our starting point as the place we'll restart the receiver */
+ if(restart_required)
+ rx_to_start = nic->rx_to_clean;
+
/* Alloc new skbs to refill list */
for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
if(unlikely(e100_rx_alloc_skb(nic, rx)))
break; /* Better luck next time (see watchdog) */
}
- e100_start_receiver(nic);
+ if(restart_required) {
+ // ack the rnr?
+ writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
+ e100_start_receiver(nic, rx_to_start);
+ if(work_done)
+ (*work_done)++;
+ }
}
static void e100_rx_clean_list(struct nic *nic)
struct rx *rx;
unsigned int i, count = nic->params.rfds.count;
+ nic->ru_running = RU_UNINITIALIZED;
+
if(nic->rxs) {
for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
if(rx->skb) {
}
nic->rx_to_use = nic->rx_to_clean = NULL;
- nic->ru_running = 0;
}
static int e100_rx_alloc_list(struct nic *nic)
unsigned int i, count = nic->params.rfds.count;
nic->rx_to_use = nic->rx_to_clean = NULL;
+ nic->ru_running = RU_UNINITIALIZED;
if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
return -ENOMEM;
}
nic->rx_to_use = nic->rx_to_clean = nic->rxs;
+ nic->ru_running = RU_SUSPENDED;
return 0;
}
static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *netdev = dev_id;
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
u8 stat_ack = readb(&nic->csr->scb.stat_ack);
DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
/* We hit Receive No Resource (RNR); restart RU after cleaning */
if(stat_ack & stat_ack_rnr)
- nic->ru_running = 0;
+ nic->ru_running = RU_SUSPENDED;
-#ifdef CONFIG_E100_NAPI
e100_disable_irq(nic);
netif_rx_schedule(netdev);
-#else
- if(stat_ack & stat_ack_rx)
- e100_rx_clean(nic, NULL, 0);
- if(stat_ack & stat_ack_tx)
- e100_tx_clean(nic);
-#endif
return IRQ_HANDLED;
}
-#ifdef CONFIG_E100_NAPI
static int e100_poll(struct net_device *netdev, int *budget)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
unsigned int work_to_do = min(netdev->quota, *budget);
unsigned int work_done = 0;
int tx_cleaned;
return 1;
}
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
static void e100_netpoll(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
e100_disable_irq(nic);
e100_intr(nic->pdev->irq, netdev, NULL);
+ e100_tx_clean(nic);
e100_enable_irq(nic);
}
#endif
static struct net_device_stats *e100_get_stats(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
return &nic->net_stats;
}
static int e100_set_mac_address(struct net_device *netdev, void *p)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
return 0;
}
+#ifdef CONFIG_PM
static int e100_asf(struct nic *nic)
{
/* ASF can be enabled from eeprom */
- return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1055) &&
+ return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) &&
(nic->eeprom[eeprom_config_asf] & eeprom_asf) &&
!(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
}
+#endif
static int e100_up(struct nic *nic)
{
if((err = e100_hw_init(nic)))
goto err_clean_cbs;
e100_set_multicast_list(nic->netdev);
- e100_start_receiver(nic);
- netif_start_queue(nic->netdev);
+ e100_start_receiver(nic, 0);
mod_timer(&nic->watchdog, jiffies);
if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
nic->netdev->name, nic->netdev)))
goto err_no_irq;
+ netif_wake_queue(nic->netdev);
+ netif_poll_enable(nic->netdev);
+ /* enable ints _after_ enabling poll, preventing a race between
+ * disable ints+schedule */
e100_enable_irq(nic);
return 0;
err_no_irq:
del_timer_sync(&nic->watchdog);
- netif_stop_queue(nic->netdev);
err_clean_cbs:
e100_clean_cbs(nic);
err_rx_clean_list:
static void e100_down(struct nic *nic)
{
+ /* wait here for poll to complete */
+ netif_poll_disable(nic->netdev);
+ netif_stop_queue(nic->netdev);
e100_hw_reset(nic);
free_irq(nic->pdev->irq, nic->netdev);
del_timer_sync(&nic->watchdog);
netif_carrier_off(nic->netdev);
- netif_stop_queue(nic->netdev);
e100_clean_cbs(nic);
e100_rx_clean_list(nic);
}
static void e100_tx_timeout(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
+
+ /* Reset outside of interrupt context, to avoid request_irq
+ * in interrupt context */
+ schedule_work(&nic->tx_timeout_task);
+}
+
+static void e100_tx_timeout_task(struct net_device *netdev)
+{
+ struct nic *nic = netdev_priv(netdev);
DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
readb(&nic->csr->scb.status));
- e100_down(netdev->priv);
- e100_up(netdev->priv);
+ e100_down(netdev_priv(netdev));
+ e100_up(netdev_priv(netdev));
}
static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
BMCR_LOOPBACK);
- e100_start_receiver(nic);
+ e100_start_receiver(nic, 0);
if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
err = -ENOMEM;
memset(skb->data, 0xFF, ETH_DATA_LEN);
e100_xmit_frame(skb, nic->netdev);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 100 + 1);
+ msleep(10);
if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
skb->data, ETH_DATA_LEN))
- err = -EAGAIN;
+ err = -EAGAIN;
err_loopback_none:
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0);
static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
return mii_ethtool_gset(&nic->mii, cmd);
}
static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
int err;
mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET);
static void e100_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
strcpy(info->fw_version, "N/A");
static int e100_get_regs_len(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
#define E100_PHY_REGS 0x1C
#define E100_REGS_LEN 1 + E100_PHY_REGS + \
sizeof(nic->mem->dump_buf) / sizeof(u32)
static void e100_get_regs(struct net_device *netdev,
struct ethtool_regs *regs, void *p)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
u32 *buff = p;
int i;
mdio_read(netdev, nic->mii.phy_id, i);
memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf));
e100_exec_cb(nic, NULL, e100_dump);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 100 + 1);
+ msleep(10);
memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf,
sizeof(nic->mem->dump_buf));
}
static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
wol->supported = (nic->mac >= mac_82558_D101_A4) ? WAKE_MAGIC : 0;
wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0;
}
static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
return -EOPNOTSUPP;
else
nic->flags &= ~wol_magic;
- pci_enable_wake(nic->pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
e100_exec_cb(nic, NULL, e100_configure);
return 0;
static u32 e100_get_msglevel(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
return nic->msg_enable;
}
static void e100_set_msglevel(struct net_device *netdev, u32 value)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
nic->msg_enable = value;
}
static int e100_nway_reset(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
return mii_nway_restart(&nic->mii);
}
static u32 e100_get_link(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
return mii_link_ok(&nic->mii);
}
static int e100_get_eeprom_len(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
return nic->eeprom_wc << 1;
}
static int e100_get_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, u8 *bytes)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
eeprom->magic = E100_EEPROM_MAGIC;
memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len);
static int e100_set_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, u8 *bytes)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
if(eeprom->magic != E100_EEPROM_MAGIC)
return -EINVAL;
+
memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len);
return e100_eeprom_save(nic, eeprom->offset >> 1,
static void e100_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
struct param_range *rfds = &nic->params.rfds;
struct param_range *cbs = &nic->params.cbs;
static int e100_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
struct param_range *rfds = &nic->params.rfds;
struct param_range *cbs = &nic->params.cbs;
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+ return -EINVAL;
+
if(netif_running(netdev))
e100_down(nic);
rfds->count = max(ring->rx_pending, rfds->min);
rfds->count = min(rfds->count, rfds->max);
cbs->count = max(ring->tx_pending, cbs->min);
cbs->count = min(cbs->count, cbs->max);
+ DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n",
+ rfds->count, cbs->count);
if(netif_running(netdev))
e100_up(nic);
static void e100_diag_test(struct net_device *netdev,
struct ethtool_test *test, u64 *data)
{
- struct nic *nic = netdev->priv;
- int i;
+ struct ethtool_cmd cmd;
+ struct nic *nic = netdev_priv(netdev);
+ int i, err;
memset(data, 0, E100_TEST_LEN * sizeof(u64));
data[0] = !mii_link_ok(&nic->mii);
data[1] = e100_eeprom_load(nic);
if(test->flags & ETH_TEST_FL_OFFLINE) {
+
+ /* save speed, duplex & autoneg settings */
+ err = mii_ethtool_gset(&nic->mii, &cmd);
+
if(netif_running(netdev))
e100_down(nic);
data[2] = e100_self_test(nic);
data[3] = e100_loopback_test(nic, lb_mac);
data[4] = e100_loopback_test(nic, lb_phy);
+
+ /* restore speed, duplex & autoneg settings */
+ err = mii_ethtool_sset(&nic->mii, &cmd);
+
if(netif_running(netdev))
e100_up(nic);
}
static int e100_phys_id(struct net_device *netdev, u32 data)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
mod_timer(&nic->blink_timer, jiffies);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(data * HZ);
+ msleep_interruptible(data * 1000);
del_timer_sync(&nic->blink_timer);
mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0);
static void e100_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *data)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
int i;
for(i = 0; i < E100_NET_STATS_LEN; i++)
static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
- struct nic *nic = netdev->priv;
- struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr->ifr_data;
+ struct nic *nic = netdev_priv(netdev);
- return generic_mii_ioctl(&nic->mii, mii, cmd, NULL);
+ return generic_mii_ioctl(&nic->mii, if_mii(ifr), cmd, NULL);
}
static int e100_alloc(struct nic *nic)
static int e100_open(struct net_device *netdev)
{
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
int err = 0;
netif_carrier_off(netdev);
static int e100_close(struct net_device *netdev)
{
- e100_down(netdev->priv);
+ e100_down(netdev_priv(netdev));
return 0;
}
SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
netdev->tx_timeout = e100_tx_timeout;
netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
-#ifdef CONFIG_E100_NAPI
netdev->poll = e100_poll;
netdev->weight = E100_NAPI_WEIGHT;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = e100_netpoll;
#endif
+ strcpy(netdev->name, pci_name(pdev));
- nic = netdev->priv;
+ nic = netdev_priv(netdev);
nic->netdev = netdev;
nic->pdev = pdev;
nic->msg_enable = (1 << debug) - 1;
goto err_out_disable_pdev;
}
- pci_set_master(pdev);
-
if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) {
DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
else
nic->flags &= ~ich;
+ e100_get_defaults(nic);
+
+ /* locks must be initialized before calling hw_reset */
spin_lock_init(&nic->cb_lock);
spin_lock_init(&nic->cmd_lock);
+ /* Reset the device before pci_set_master() in case device is in some
+ * funky state and has an interrupt pending - hint: we don't have the
+ * interrupt handler registered yet. */
+ e100_hw_reset(nic);
+
+ pci_set_master(pdev);
+
init_timer(&nic->watchdog);
nic->watchdog.function = e100_watchdog;
nic->watchdog.data = (unsigned long)nic;
nic->blink_timer.function = e100_blink_led;
nic->blink_timer.data = (unsigned long)nic;
+ INIT_WORK(&nic->tx_timeout_task,
+ (void (*)(void *))e100_tx_timeout_task, netdev);
+
if((err = e100_alloc(nic))) {
DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
goto err_out_iounmap;
}
- e100_get_defaults(nic);
- e100_hw_reset(nic);
e100_phy_init(nic);
if((err = e100_eeprom_load(nic)))
goto err_out_free;
- ((u16 *)netdev->dev_addr)[0] = le16_to_cpu(nic->eeprom[0]);
- ((u16 *)netdev->dev_addr)[1] = le16_to_cpu(nic->eeprom[1]);
- ((u16 *)netdev->dev_addr)[2] = le16_to_cpu(nic->eeprom[2]);
+
+ memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
if(!is_valid_ether_addr(netdev->dev_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC address from "
"EEPROM, aborting.\n");
(nic->eeprom[eeprom_id] & eeprom_id_wol))
nic->flags |= wol_magic;
- pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+ /* ack any pending wake events, disable PME */
+ pci_enable_wake(pdev, 0, 0);
+ strcpy(netdev->name, "eth%d");
if((err = register_netdev(netdev))) {
DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
goto err_out_free;
struct net_device *netdev = pci_get_drvdata(pdev);
if(netdev) {
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
unregister_netdev(netdev);
e100_free(nic);
iounmap(nic->csr);
}
#ifdef CONFIG_PM
-static int e100_suspend(struct pci_dev *pdev, u32 state)
+static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
if(netif_running(netdev))
e100_down(nic);
e100_hw_reset(nic);
netif_device_detach(netdev);
- pci_save_state(pdev, nic->pm_state);
- pci_enable_wake(pdev, state, nic->flags & (wol_magic | e100_asf(nic)));
+ pci_save_state(pdev);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), nic->flags & (wol_magic | e100_asf(nic)));
pci_disable_device(pdev);
- pci_set_power_state(pdev, state);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
static int e100_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct nic *nic = netdev->priv;
+ struct nic *nic = netdev_priv(netdev);
- pci_set_power_state(pdev, 0);
- pci_restore_state(pdev, nic->pm_state);
- e100_hw_init(nic);
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ /* ack any pending wake events, disable PME */
+ pci_enable_wake(pdev, 0, 0);
+ if(e100_hw_init(nic))
+ DPRINTK(HW, ERR, "e100_hw_init failed\n");
netif_device_attach(netdev);
if(netif_running(netdev))
}
#endif
+
+static void e100_shutdown(struct device *dev)
+{
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
+
+#ifdef CONFIG_PM
+ pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
+#else
+ pci_enable_wake(pdev, 0, nic->flags & (wol_magic));
+#endif
+}
+
+
static struct pci_driver e100_driver = {
.name = DRV_NAME,
.id_table = e100_id_table,
.suspend = e100_suspend,
.resume = e100_resume,
#endif
+
+ .driver = {
+ .shutdown = e100_shutdown,
+ }
+
};
static int __init e100_init_module(void)
printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
}
- return pci_module_init(&e100_driver);
+ return pci_module_init(&e100_driver);
}
static void __exit e100_cleanup_module(void)