patch-2.4.26 linux-2.4.26/drivers/net/e1000/e1000_main.c
Next file: linux-2.4.26/drivers/net/e1000/e1000_osdep.h
Previous file: linux-2.4.26/drivers/net/e1000/e1000_hw.h
Back to the patch index
Back to the overall index
- Lines: 538
- Date:
2004-04-14 06:05:30.000000000 -0700
- Orig file:
linux-2.4.25/drivers/net/e1000/e1000_main.c
- Orig date:
2003-11-28 10:26:20.000000000 -0800
diff -urN linux-2.4.25/drivers/net/e1000/e1000_main.c linux-2.4.26/drivers/net/e1000/e1000_main.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2004 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@@ -30,10 +30,24 @@
/* Change Log
*
- * 5.2.20 9/30/03
+ * 5.2.30.1 1/29/03
+ * o Set VLAN filtering to IEEE 802.1Q after reset so we don't break
+ * SoL connections that use VLANs.
+ * o Allow 1000/Full setting for AutoNeg param for Fiber connections
+ * Jon D Mason [jonmason@us.ibm.com].
+ * o Race between Tx queue and Tx clean fixed with a spin lock.
+ * o Added netpoll support.
+ * o Fixed endianess bug causing ethtool loopback diags to fail on ppc.
+ * o Use pdev->irq rather than netdev->irq in preparation for MSI support.
+ * o Report driver message on user override of InterruptThrottleRate
+ * module parameter.
+ * o Change I/O address storage from uint32_t to unsigned long.
+ *
+ * 5.2.22 10/15/03
* o Bug fix: SERDES devices might be connected to a back-plane
* switch that doesn't support auto-neg, so add the capability
- * to force 1000/Full.
+ * to force 1000/Full. Also, since forcing 1000/Full, sample
+ * RxSynchronize bit to detect link state.
* o Bug fix: Flow control settings for hi/lo watermark didn't
* consider changes in the Rx FIFO size, which could occur with
* Jumbo Frames or with the reduced FIFO in 82547.
@@ -42,30 +56,19 @@
* o Bug fix: hang under heavy Tx stress when running out of Tx
* descriptors; wasn't clearing context descriptor when backing
* out of send because of no-resource condition.
+ * o Bug fix: check netif_running in dev->poll so we don't have to
+ * hang in dev->close until all polls are finished. [Robert
+ * Ollson (robert.olsson@data.slu.se)].
+ * o Revert TxDescriptor ring size back to 256 since change to 1024
+ * wasn't accepted into the kernel.
*
* 5.2.16 8/8/03
- * o Added support for new controllers: 82545GM, 82546GB, 82541/7_B1
- * o Bug fix: reset h/w before first EEPROM read because we don't know
- * who may have been messing with the device before we got there.
- * [Dave Johnson (ddj -a-t- cascv.brown.edu)]
- * o Bug fix: read the correct work from EEPROM to detect programmed
- * WoL settings.
- * o Bug fix: TSO would hang if space left in FIFO was being miscalculated
- * when mss dropped without a correspoding drop in the DMA buffer size.
- * o ASF for Fiber nics isn't supported.
- * o Bug fix: Workaround added for potential hang with 82544 running in
- * PCI-X if send buffer terminates within an evenly-aligned dword.
- * o Feature: Add support for ethtool flow control setting.
- * o Feature: Add support for ethtool TSO setting.
- * o Feature: Increase default Tx Descriptor count to 1024 for >= 82544.
- *
- * 5.1.13 5/28/03
*/
char e1000_driver_name[] = "e1000";
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.2.20-k1";
-char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
+char e1000_driver_version[] = "5.2.30.1-k1";
+char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
@@ -89,7 +92,6 @@
{0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -113,12 +115,17 @@
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
-/* Local Function Prototypes */
-
int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
void e1000_reset(struct e1000_adapter *adapter);
int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
+int e1000_setup_tx_resources(struct e1000_adapter *adapter);
+int e1000_setup_rx_resources(struct e1000_adapter *adapter);
+void e1000_free_tx_resources(struct e1000_adapter *adapter);
+void e1000_free_rx_resources(struct e1000_adapter *adapter);
+void e1000_update_stats(struct e1000_adapter *adapter);
+
+/* Local Function Prototypes */
static int e1000_init_module(void);
static void e1000_exit_module(void);
@@ -127,15 +134,11 @@
static int e1000_sw_init(struct e1000_adapter *adapter);
static int e1000_open(struct net_device *netdev);
static int e1000_close(struct net_device *netdev);
-static int e1000_setup_tx_resources(struct e1000_adapter *adapter);
-static int e1000_setup_rx_resources(struct e1000_adapter *adapter);
static void e1000_configure_tx(struct e1000_adapter *adapter);
static void e1000_configure_rx(struct e1000_adapter *adapter);
static void e1000_setup_rctl(struct e1000_adapter *adapter);
static void e1000_clean_tx_ring(struct e1000_adapter *adapter);
static void e1000_clean_rx_ring(struct e1000_adapter *adapter);
-static void e1000_free_tx_resources(struct e1000_adapter *adapter);
-static void e1000_free_rx_resources(struct e1000_adapter *adapter);
static void e1000_set_multi(struct net_device *netdev);
static void e1000_update_phy_info(unsigned long data);
static void e1000_watchdog(unsigned long data);
@@ -144,7 +147,6 @@
static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
static int e1000_set_mac(struct net_device *netdev, void *p);
-static void e1000_update_stats(struct e1000_adapter *adapter);
static inline void e1000_irq_disable(struct e1000_adapter *adapter);
static inline void e1000_irq_enable(struct e1000_adapter *adapter);
static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
@@ -182,6 +184,11 @@
static int e1000_resume(struct pci_dev *pdev);
#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/* for netdump / net console */
+static void e1000_netpoll (struct net_device *dev);
+#endif
+
struct notifier_block e1000_notifier_reboot = {
.notifier_call = e1000_notify_reboot,
.next = NULL,
@@ -268,7 +275,7 @@
e1000_configure_rx(adapter);
e1000_alloc_rx_buffers(adapter);
- if((err = request_irq(netdev->irq, &e1000_intr,
+ if((err = request_irq(adapter->pdev->irq, &e1000_intr,
SA_SHIRQ | SA_SAMPLE_RANDOM,
netdev->name, netdev)))
return err;
@@ -285,7 +292,7 @@
struct net_device *netdev = adapter->netdev;
e1000_irq_disable(adapter);
- free_irq(netdev->irq, netdev);
+ free_irq(adapter->pdev->irq, netdev);
del_timer_sync(&adapter->tx_fifo_stall_timer);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
@@ -336,6 +343,10 @@
if(adapter->hw.mac_type >= e1000_82544)
E1000_WRITE_REG(&adapter->hw, WUC, 0);
e1000_init_hw(&adapter->hw);
+
+ /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
+ E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
+
e1000_reset_adaptive(&adapter->hw);
e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
}
@@ -433,8 +444,10 @@
netdev->vlan_rx_register = e1000_vlan_rx_register;
netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = e1000_netpoll;
+#endif
- netdev->irq = pdev->irq;
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len;
netdev->base_addr = adapter->hw.io_base;
@@ -668,6 +681,7 @@
atomic_set(&adapter->irq_sem, 1);
spin_lock_init(&adapter->stats_lock);
+ spin_lock_init(&adapter->tx_lock);
return 0;
}
@@ -748,7 +762,7 @@
* Return 0 on success, negative on failure
**/
-static int
+int
e1000_setup_tx_resources(struct e1000_adapter *adapter)
{
struct e1000_desc_ring *txdr = &adapter->tx_ring;
@@ -865,7 +879,7 @@
* Returns 0 on success, negative on failure
**/
-static int
+int
e1000_setup_rx_resources(struct e1000_adapter *adapter)
{
struct e1000_desc_ring *rxdr = &adapter->rx_ring;
@@ -1004,7 +1018,7 @@
* Free all transmit software resources
**/
-static void
+void
e1000_free_tx_resources(struct e1000_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
@@ -1072,7 +1086,7 @@
* Free all receive software resources
**/
-static void
+void
e1000_free_rx_resources(struct e1000_adapter *adapter)
{
struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
@@ -1280,41 +1294,6 @@
e1000_leave_82542_rst(adapter);
}
-static void
-e1000_tx_flush(struct e1000_adapter *adapter)
-{
- uint32_t ctrl, tctl, txcw, icr;
-
- e1000_irq_disable(adapter);
-
- if(adapter->hw.mac_type < e1000_82543) {
- /* Transmit Unit Reset */
- tctl = E1000_READ_REG(&adapter->hw, TCTL);
- E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST);
- E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
- e1000_clean_tx_ring(adapter);
- e1000_configure_tx(adapter);
- } else {
- txcw = E1000_READ_REG(&adapter->hw, TXCW);
- E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE);
-
- ctrl = E1000_READ_REG(&adapter->hw, CTRL);
- E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU |
- E1000_CTRL_ILOS);
-
- mdelay(10);
-
- e1000_clean_tx_irq(adapter);
- E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
- E1000_WRITE_REG(&adapter->hw, TXCW, txcw);
-
- /* clear the link status change interrupts this caused */
- icr = E1000_READ_REG(&adapter->hw, ICR);
- }
-
- e1000_irq_enable(adapter);
-}
-
/* need to wait a few seconds after link up to get diagnostic information from the phy */
static void
@@ -1378,10 +1357,17 @@
struct net_device *netdev = adapter->netdev;
struct e1000_desc_ring *txdr = &adapter->tx_ring;
unsigned int i;
+ uint32_t link;
e1000_check_for_link(&adapter->hw);
- if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
+ if((adapter->hw.media_type == e1000_media_type_internal_serdes) &&
+ !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE))
+ link = !adapter->hw.serdes_link_down;
+ else
+ link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU;
+
+ if(link) {
if(!netif_carrier_ok(netdev)) {
e1000_get_speed_and_duplex(&adapter->hw,
&adapter->link_speed,
@@ -1414,14 +1400,26 @@
}
e1000_update_stats(adapter);
+
+ adapter->hw.tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
+ adapter->tpt_old = adapter->stats.tpt;
+ adapter->hw.collision_delta = adapter->stats.colc - adapter->colc_old;
+ adapter->colc_old = adapter->stats.colc;
+
+ adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old;
+ adapter->gorcl_old = adapter->stats.gorcl;
+ adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old;
+ adapter->gotcl_old = adapter->stats.gotcl;
+
e1000_update_adaptive(&adapter->hw);
if(!netif_carrier_ok(netdev)) {
if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) {
- unsigned long flags;
- spin_lock_irqsave(&netdev->xmit_lock, flags);
- e1000_tx_flush(adapter);
- spin_unlock_irqrestore(&netdev->xmit_lock, flags);
+ /* We've lost link, so the controller stops DMA,
+ * but we've got queued Tx work that's never going
+ * to get done, so reset controller to flush Tx.
+ * (Do the reset outside of interrupt context). */
+ schedule_task(&adapter->tx_timeout_task);
}
}
@@ -1685,7 +1683,7 @@
i = (i == 0) ? tx_ring->count - 1 : i - 1;
tx_ring->buffer_info[i].skb = skb;
tx_ring->buffer_info[first].next_to_watch = i;
-
+
return count;
}
@@ -1782,6 +1780,7 @@
struct e1000_adapter *adapter = netdev->priv;
unsigned int first;
unsigned int tx_flags = 0;
+ unsigned long flags;
int count;
if(skb->len <= 0) {
@@ -1789,10 +1788,13 @@
return 0;
}
+ spin_lock_irqsave(&adapter->tx_lock, flags);
+
if(adapter->hw.mac_type == e1000_82547) {
if(e1000_82547_fifo_workaround(adapter, skb)) {
netif_stop_queue(netdev);
mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
return 1;
}
}
@@ -1813,11 +1815,14 @@
e1000_tx_queue(adapter, count, tx_flags);
else {
netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
return 1;
}
netdev->trans_start = jiffies;
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+
return 0;
}
@@ -1859,6 +1864,7 @@
{
struct e1000_adapter *adapter = netdev->priv;
+ e1000_update_stats(adapter);
return &adapter->net_stats;
}
@@ -1917,7 +1923,7 @@
* @adapter: board private structure
**/
-static void
+void
e1000_update_stats(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -1935,8 +1941,7 @@
adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS);
adapter->stats.gprc += E1000_READ_REG(hw, GPRC);
- adapter->gorcl = E1000_READ_REG(hw, GORCL);
- adapter->stats.gorcl += adapter->gorcl;
+ adapter->stats.gorcl += E1000_READ_REG(hw, GORCL);
adapter->stats.gorch += E1000_READ_REG(hw, GORCH);
adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
@@ -1948,8 +1953,6 @@
adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
- spin_unlock_irqrestore(&adapter->stats_lock, flags);
-
/* the rest of the counters are only modified here */
adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
@@ -1967,8 +1970,7 @@
adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC);
adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC);
adapter->stats.gptc += E1000_READ_REG(hw, GPTC);
- adapter->gotcl = E1000_READ_REG(hw, GOTCL);
- adapter->stats.gotcl += adapter->gotcl;
+ adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL);
adapter->stats.gotch += E1000_READ_REG(hw, GOTCH);
adapter->stats.rnbc += E1000_READ_REG(hw, RNBC);
adapter->stats.ruc += E1000_READ_REG(hw, RUC);
@@ -2050,6 +2052,8 @@
!e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
adapter->phy_stats.receive_errors += phy_tmp;
}
+
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
}
/**
@@ -2092,6 +2096,7 @@
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_hw *hw = &adapter->hw;
uint32_t icr = E1000_READ_REG(&adapter->hw, ICR);
#ifndef CONFIG_E1000_NAPI
unsigned int i;
@@ -2101,7 +2106,7 @@
return IRQ_NONE; /* Not our interrupt */
if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
- adapter->hw.get_link_status = 1;
+ hw->get_link_status = 1;
mod_timer(&adapter->watchdog_timer, jiffies);
}
@@ -2113,14 +2118,30 @@
*/
atomic_inc(&adapter->irq_sem);
- E1000_WRITE_REG(&adapter->hw, IMC, ~0);
+ E1000_WRITE_REG(hw, IMC, ~0);
__netif_rx_schedule(netdev);
}
#else
+ /* Writing IMC and IMS is needed for 82547.
+ Due to Hub Link bus being occupied, an interrupt
+ de-assertion message is not able to be sent.
+ When an interrupt assertion message is generated later,
+ two messages are re-ordered and sent out.
+ That causes APIC to think 82547 is in de-assertion
+ state, while 82547 is in assertion state, resulting
+ in dead lock. Writing IMC forces 82547 into
+ de-assertion state.
+ */
+ if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
+ e1000_irq_disable(adapter);
+
for(i = 0; i < E1000_MAX_INTR; i++)
if(!e1000_clean_rx_irq(adapter) &
!e1000_clean_tx_irq(adapter))
break;
+
+ if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
+ e1000_irq_enable(adapter);
#endif
return IRQ_HANDLED;
@@ -2145,7 +2166,7 @@
*budget -= work_done;
netdev->quota -= work_done;
- if(work_done < work_to_do) {
+ if(work_done < work_to_do || !netif_running(netdev)) {
netif_rx_complete(netdev);
e1000_irq_enable(adapter);
}
@@ -2170,6 +2191,8 @@
unsigned int i, eop;
boolean_t cleaned = FALSE;
+ spin_lock(&adapter->tx_lock);
+
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -2214,6 +2237,8 @@
if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))
netif_wake_queue(netdev);
+ spin_unlock(&adapter->tx_lock);
+
return cleaned;
}
@@ -2641,13 +2666,13 @@
}
uint32_t
-e1000_io_read(struct e1000_hw *hw, uint32_t port)
+e1000_io_read(struct e1000_hw *hw, unsigned long port)
{
return inl(port);
}
void
-e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value)
+e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value)
{
outl(value, port);
}
@@ -2664,8 +2689,6 @@
if(grp) {
/* enable VLAN tag insert/strip */
- E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
-
ctrl = E1000_READ_REG(&adapter->hw, CTRL);
ctrl |= E1000_CTRL_VME;
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
@@ -2899,4 +2922,20 @@
}
#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+static void e1000_netpoll (struct net_device *dev)
+{
+ struct e1000_adapter *adapter = dev->priv;
+ disable_irq(adapter->pdev->irq);
+ e1000_intr (adapter->pdev->irq, dev, NULL);
+ enable_irq(adapter->pdev->irq);
+}
+#endif
+
/* e1000_main.c */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)