aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/e1000
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/intel/e1000')
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000.h1
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.c156
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.h10
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c249
4 files changed, 320 insertions, 96 deletions
diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h
index 1e1596990b5c..2b6cd02bfba0 100644
--- a/drivers/net/ethernet/intel/e1000/e1000.h
+++ b/drivers/net/ethernet/intel/e1000/e1000.h
@@ -254,6 +254,7 @@ struct e1000_adapter {
atomic_t tx_fifo_stall;
bool pcix_82544;
bool detect_tx_hung;
+ bool dump_buffers;
/* RX */
bool (*clean_rx)(struct e1000_adapter *adapter,
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 36ee76bf4cba..c526279e4927 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -5253,6 +5253,78 @@ static s32 e1000_check_downshift(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+static const u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {
+ IGP01E1000_PHY_AGC_PARAM_A,
+ IGP01E1000_PHY_AGC_PARAM_B,
+ IGP01E1000_PHY_AGC_PARAM_C,
+ IGP01E1000_PHY_AGC_PARAM_D
+};
+
+static s32 e1000_1000Mb_check_cable_length(struct e1000_hw *hw)
+{
+ u16 min_length, max_length;
+ u16 phy_data, i;
+ s32 ret_val;
+
+ ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
+ if (ret_val)
+ return ret_val;
+
+ if (hw->dsp_config_state != e1000_dsp_config_enabled)
+ return 0;
+
+ if (min_length >= e1000_igp_cable_length_50) {
+ for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i],
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
+
+ ret_val = e1000_write_phy_reg(hw, dsp_reg_array[i],
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+ hw->dsp_config_state = e1000_dsp_config_activated;
+ } else {
+ u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
+ u32 idle_errs = 0;
+
+ /* clear previous idle error counts */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ for (i = 0; i < ffe_idle_err_timeout; i++) {
+ udelay(1000);
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
+ if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
+ hw->ffe_config_state = e1000_ffe_config_active;
+
+ ret_val = e1000_write_phy_reg(hw,
+ IGP01E1000_PHY_DSP_FFE,
+ IGP01E1000_PHY_DSP_FFE_CM_CP);
+ if (ret_val)
+ return ret_val;
+ break;
+ }
+
+ if (idle_errs)
+ ffe_idle_err_timeout =
+ FFE_IDLE_ERR_COUNT_TIMEOUT_100;
+ }
+ }
+
+ return 0;
+}
+
/**
* e1000_config_dsp_after_link_change
* @hw: Struct containing variables accessed by shared code
@@ -5269,13 +5341,6 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
{
s32 ret_val;
u16 phy_data, phy_saved_data, speed, duplex, i;
- static const u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {
- IGP01E1000_PHY_AGC_PARAM_A,
- IGP01E1000_PHY_AGC_PARAM_B,
- IGP01E1000_PHY_AGC_PARAM_C,
- IGP01E1000_PHY_AGC_PARAM_D
- };
- u16 min_length, max_length;
e_dbg("e1000_config_dsp_after_link_change");
@@ -5290,84 +5355,9 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
}
if (speed == SPEED_1000) {
-
- ret_val =
- e1000_get_cable_length(hw, &min_length,
- &max_length);
+ ret_val = e1000_1000Mb_check_cable_length(hw);
if (ret_val)
return ret_val;
-
- if ((hw->dsp_config_state == e1000_dsp_config_enabled)
- && min_length >= e1000_igp_cable_length_50) {
-
- for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
- ret_val =
- e1000_read_phy_reg(hw,
- dsp_reg_array[i],
- &phy_data);
- if (ret_val)
- return ret_val;
-
- phy_data &=
- ~IGP01E1000_PHY_EDAC_MU_INDEX;
-
- ret_val =
- e1000_write_phy_reg(hw,
- dsp_reg_array
- [i], phy_data);
- if (ret_val)
- return ret_val;
- }
- hw->dsp_config_state =
- e1000_dsp_config_activated;
- }
-
- if ((hw->ffe_config_state == e1000_ffe_config_enabled)
- && (min_length < e1000_igp_cable_length_50)) {
-
- u16 ffe_idle_err_timeout =
- FFE_IDLE_ERR_COUNT_TIMEOUT_20;
- u32 idle_errs = 0;
-
- /* clear previous idle error counts */
- ret_val =
- e1000_read_phy_reg(hw, PHY_1000T_STATUS,
- &phy_data);
- if (ret_val)
- return ret_val;
-
- for (i = 0; i < ffe_idle_err_timeout; i++) {
- udelay(1000);
- ret_val =
- e1000_read_phy_reg(hw,
- PHY_1000T_STATUS,
- &phy_data);
- if (ret_val)
- return ret_val;
-
- idle_errs +=
- (phy_data &
- SR_1000T_IDLE_ERROR_CNT);
- if (idle_errs >
- SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT)
- {
- hw->ffe_config_state =
- e1000_ffe_config_active;
-
- ret_val =
- e1000_write_phy_reg(hw,
- IGP01E1000_PHY_DSP_FFE,
- IGP01E1000_PHY_DSP_FFE_CM_CP);
- if (ret_val)
- return ret_val;
- break;
- }
-
- if (idle_errs)
- ffe_idle_err_timeout =
- FFE_IDLE_ERR_COUNT_TIMEOUT_100;
- }
- }
}
} else {
if (hw->dsp_config_state == e1000_dsp_config_activated) {
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.h b/drivers/net/ethernet/intel/e1000/e1000_hw.h
index f6c4d7e2560c..11578c8978db 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.h
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.h
@@ -895,6 +895,11 @@ struct e1000_ffvt_entry {
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */
+#define E1000_RDFH 0x02410 /* RX Data FIFO Head - RW */
+#define E1000_RDFT 0x02418 /* RX Data FIFO Tail - RW */
+#define E1000_RDFHS 0x02420 /* RX Data FIFO Head Saved - RW */
+#define E1000_RDFTS 0x02428 /* RX Data FIFO Tail Saved - RW */
+#define E1000_RDFPC 0x02430 /* RX Data FIFO Packet Count - RW */
#define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */
#define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */
#define E1000_RDLEN 0x02808 /* RX Descriptor Length - RW */
@@ -1074,6 +1079,11 @@ struct e1000_ffvt_entry {
#define E1000_82542_IMC E1000_IMC
#define E1000_82542_RCTL E1000_RCTL
#define E1000_82542_RDTR 0x00108
+#define E1000_82542_RDFH E1000_RDFH
+#define E1000_82542_RDFT E1000_RDFT
+#define E1000_82542_RDFHS E1000_RDFHS
+#define E1000_82542_RDFTS E1000_RDFTS
+#define E1000_82542_RDFPC E1000_RDFPC
#define E1000_82542_RDBAL 0x00110
#define E1000_82542_RDBAH 0x00114
#define E1000_82542_RDLEN 0x00118
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index ef274d8255ba..0e9aec8f6917 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -730,10 +730,8 @@ static void e1000_dump_eeprom(struct e1000_adapter *adapter)
eeprom.offset = 0;
data = kmalloc(eeprom.len, GFP_KERNEL);
- if (!data) {
- pr_err("Unable to allocate memory to dump EEPROM data\n");
+ if (!data)
return;
- }
ops->get_eeprom(netdev, &eeprom, data);
@@ -1069,8 +1067,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
(hw->mac_type != e1000_82547))
netdev->hw_features |= NETIF_F_TSO;
+ netdev->priv_flags |= IFF_SUPP_NOFCS;
+
netdev->features |= netdev->hw_features;
netdev->hw_features |= NETIF_F_RXCSUM;
+ netdev->hw_features |= NETIF_F_RXFCS;
if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
@@ -2694,6 +2695,7 @@ set_itr_now:
#define E1000_TX_FLAGS_VLAN 0x00000002
#define E1000_TX_FLAGS_TSO 0x00000004
#define E1000_TX_FLAGS_IPV4 0x00000008
+#define E1000_TX_FLAGS_NO_FCS 0x00000010
#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000
#define E1000_TX_FLAGS_VLAN_SHIFT 16
@@ -2995,6 +2997,9 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
}
+ if (unlikely(tx_flags & E1000_TX_FLAGS_NO_FCS))
+ txd_lower &= ~(E1000_TXD_CMD_IFCS);
+
i = tx_ring->next_to_use;
while (count--) {
@@ -3009,6 +3014,10 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
+ /* txd_cmd re-enables FCS, so we'll re-disable it here as desired. */
+ if (unlikely(tx_flags & E1000_TX_FLAGS_NO_FCS))
+ tx_desc->lower.data &= ~(cpu_to_le32(E1000_TXD_CMD_IFCS));
+
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
@@ -3224,6 +3233,9 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
if (likely(skb->protocol == htons(ETH_P_IP)))
tx_flags |= E1000_TX_FLAGS_IPV4;
+ if (unlikely(skb->no_fcs))
+ tx_flags |= E1000_TX_FLAGS_NO_FCS;
+
count = e1000_tx_map(adapter, tx_ring, skb, first, max_per_txd,
nr_frags, mss);
@@ -3241,6 +3253,215 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+#define NUM_REGS 38 /* 1 based count */
+static void e1000_regdump(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 regs[NUM_REGS];
+ u32 *regs_buff = regs;
+ int i = 0;
+
+ static const char * const reg_name[] = {
+ "CTRL", "STATUS",
+ "RCTL", "RDLEN", "RDH", "RDT", "RDTR",
+ "TCTL", "TDBAL", "TDBAH", "TDLEN", "TDH", "TDT",
+ "TIDV", "TXDCTL", "TADV", "TARC0",
+ "TDBAL1", "TDBAH1", "TDLEN1", "TDH1", "TDT1",
+ "TXDCTL1", "TARC1",
+ "CTRL_EXT", "ERT", "RDBAL", "RDBAH",
+ "TDFH", "TDFT", "TDFHS", "TDFTS", "TDFPC",
+ "RDFH", "RDFT", "RDFHS", "RDFTS", "RDFPC"
+ };
+
+ regs_buff[0] = er32(CTRL);
+ regs_buff[1] = er32(STATUS);
+
+ regs_buff[2] = er32(RCTL);
+ regs_buff[3] = er32(RDLEN);
+ regs_buff[4] = er32(RDH);
+ regs_buff[5] = er32(RDT);
+ regs_buff[6] = er32(RDTR);
+
+ regs_buff[7] = er32(TCTL);
+ regs_buff[8] = er32(TDBAL);
+ regs_buff[9] = er32(TDBAH);
+ regs_buff[10] = er32(TDLEN);
+ regs_buff[11] = er32(TDH);
+ regs_buff[12] = er32(TDT);
+ regs_buff[13] = er32(TIDV);
+ regs_buff[14] = er32(TXDCTL);
+ regs_buff[15] = er32(TADV);
+ regs_buff[16] = er32(TARC0);
+
+ regs_buff[17] = er32(TDBAL1);
+ regs_buff[18] = er32(TDBAH1);
+ regs_buff[19] = er32(TDLEN1);
+ regs_buff[20] = er32(TDH1);
+ regs_buff[21] = er32(TDT1);
+ regs_buff[22] = er32(TXDCTL1);
+ regs_buff[23] = er32(TARC1);
+ regs_buff[24] = er32(CTRL_EXT);
+ regs_buff[25] = er32(ERT);
+ regs_buff[26] = er32(RDBAL0);
+ regs_buff[27] = er32(RDBAH0);
+ regs_buff[28] = er32(TDFH);
+ regs_buff[29] = er32(TDFT);
+ regs_buff[30] = er32(TDFHS);
+ regs_buff[31] = er32(TDFTS);
+ regs_buff[32] = er32(TDFPC);
+ regs_buff[33] = er32(RDFH);
+ regs_buff[34] = er32(RDFT);
+ regs_buff[35] = er32(RDFHS);
+ regs_buff[36] = er32(RDFTS);
+ regs_buff[37] = er32(RDFPC);
+
+ pr_info("Register dump\n");
+ for (i = 0; i < NUM_REGS; i++)
+ pr_info("%-15s %08x\n", reg_name[i], regs_buff[i]);
+}
+
+/*
+ * e1000_dump: Print registers, tx ring and rx ring
+ */
+static void e1000_dump(struct e1000_adapter *adapter)
+{
+ /* this code doesn't handle multiple rings */
+ struct e1000_tx_ring *tx_ring = adapter->tx_ring;
+ struct e1000_rx_ring *rx_ring = adapter->rx_ring;
+ int i;
+
+ if (!netif_msg_hw(adapter))
+ return;
+
+ /* Print Registers */
+ e1000_regdump(adapter);
+
+ /*
+ * transmit dump
+ */
+ pr_info("TX Desc ring0 dump\n");
+
+ /* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
+ *
+ * Legacy Transmit Descriptor
+ * +--------------------------------------------------------------+
+ * 0 | Buffer Address [63:0] (Reserved on Write Back) |
+ * +--------------------------------------------------------------+
+ * 8 | Special | CSS | Status | CMD | CSO | Length |
+ * +--------------------------------------------------------------+
+ * 63 48 47 36 35 32 31 24 23 16 15 0
+ *
+ * Extended Context Descriptor (DTYP=0x0) for TSO or checksum offload
+ * 63 48 47 40 39 32 31 16 15 8 7 0
+ * +----------------------------------------------------------------+
+ * 0 | TUCSE | TUCS0 | TUCSS | IPCSE | IPCS0 | IPCSS |
+ * +----------------------------------------------------------------+
+ * 8 | MSS | HDRLEN | RSV | STA | TUCMD | DTYP | PAYLEN |
+ * +----------------------------------------------------------------+
+ * 63 48 47 40 39 36 35 32 31 24 23 20 19 0
+ *
+ * Extended Data Descriptor (DTYP=0x1)
+ * +----------------------------------------------------------------+
+ * 0 | Buffer Address [63:0] |
+ * +----------------------------------------------------------------+
+ * 8 | VLAN tag | POPTS | Rsvd | Status | Command | DTYP | DTALEN |
+ * +----------------------------------------------------------------+
+ * 63 48 47 40 39 36 35 32 31 24 23 20 19 0
+ */
+ pr_info("Tc[desc] [Ce CoCsIpceCoS] [MssHlRSCm0Plen] [bi->dma ] leng ntw timestmp bi->skb\n");
+ pr_info("Td[desc] [address 63:0 ] [VlaPoRSCm1Dlen] [bi->dma ] leng ntw timestmp bi->skb\n");
+
+ if (!netif_msg_tx_done(adapter))
+ goto rx_ring_summary;
+
+ for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+ struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
+ struct e1000_buffer *buffer_info = &tx_ring->buffer_info[i];
+ struct my_u { u64 a; u64 b; };
+ struct my_u *u = (struct my_u *)tx_desc;
+ const char *type;
+
+ if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
+ type = "NTC/U";
+ else if (i == tx_ring->next_to_use)
+ type = "NTU";
+ else if (i == tx_ring->next_to_clean)
+ type = "NTC";
+ else
+ type = "";
+
+ pr_info("T%c[0x%03X] %016llX %016llX %016llX %04X %3X %016llX %p %s\n",
+ ((le64_to_cpu(u->b) & (1<<20)) ? 'd' : 'c'), i,
+ le64_to_cpu(u->a), le64_to_cpu(u->b),
+ (u64)buffer_info->dma, buffer_info->length,
+ buffer_info->next_to_watch,
+ (u64)buffer_info->time_stamp, buffer_info->skb, type);
+ }
+
+rx_ring_summary:
+ /*
+ * receive dump
+ */
+ pr_info("\nRX Desc ring dump\n");
+
+ /* Legacy Receive Descriptor Format
+ *
+ * +-----------------------------------------------------+
+ * | Buffer Address [63:0] |
+ * +-----------------------------------------------------+
+ * | VLAN Tag | Errors | Status 0 | Packet csum | Length |
+ * +-----------------------------------------------------+
+ * 63 48 47 40 39 32 31 16 15 0
+ */
+ pr_info("R[desc] [address 63:0 ] [vl er S cks ln] [bi->dma ] [bi->skb]\n");
+
+ if (!netif_msg_rx_status(adapter))
+ goto exit;
+
+ for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
+ struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
+ struct e1000_buffer *buffer_info = &rx_ring->buffer_info[i];
+ struct my_u { u64 a; u64 b; };
+ struct my_u *u = (struct my_u *)rx_desc;
+ const char *type;
+
+ if (i == rx_ring->next_to_use)
+ type = "NTU";
+ else if (i == rx_ring->next_to_clean)
+ type = "NTC";
+ else
+ type = "";
+
+ pr_info("R[0x%03X] %016llX %016llX %016llX %p %s\n",
+ i, le64_to_cpu(u->a), le64_to_cpu(u->b),
+ (u64)buffer_info->dma, buffer_info->skb, type);
+ } /* for */
+
+ /* dump the descriptor caches */
+ /* rx */
+ pr_info("Rx descriptor cache in 64bit format\n");
+ for (i = 0x6000; i <= 0x63FF ; i += 0x10) {
+ pr_info("R%04X: %08X|%08X %08X|%08X\n",
+ i,
+ readl(adapter->hw.hw_addr + i+4),
+ readl(adapter->hw.hw_addr + i),
+ readl(adapter->hw.hw_addr + i+12),
+ readl(adapter->hw.hw_addr + i+8));
+ }
+ /* tx */
+ pr_info("Tx descriptor cache in 64bit format\n");
+ for (i = 0x7000; i <= 0x73FF ; i += 0x10) {
+ pr_info("T%04X: %08X|%08X %08X|%08X\n",
+ i,
+ readl(adapter->hw.hw_addr + i+4),
+ readl(adapter->hw.hw_addr + i),
+ readl(adapter->hw.hw_addr + i+12),
+ readl(adapter->hw.hw_addr + i+8));
+ }
+exit:
+ return;
+}
+
/**
* e1000_tx_timeout - Respond to a Tx Hang
* @netdev: network interface device structure
@@ -3262,6 +3483,7 @@ static void e1000_reset_task(struct work_struct *work)
if (test_bit(__E1000_DOWN, &adapter->flags))
return;
+ e_err(drv, "Reset adapter\n");
e1000_reinit_safe(adapter);
}
@@ -3679,6 +3901,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
eop,
jiffies,
eop_desc->upper.fields.status);
+ e1000_dump(adapter);
netif_stop_queue(netdev);
}
}
@@ -3900,10 +4123,9 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
((u32)(rx_desc->errors) << 24),
le16_to_cpu(rx_desc->csum), skb);
- pskb_trim(skb, skb->len - 4);
-
- /* probably a little skewed due to removing CRC */
- total_rx_bytes += skb->len;
+ total_rx_bytes += (skb->len - 4); /* don't count FCS */
+ if (likely(!(netdev->features & NETIF_F_RXFCS)))
+ pskb_trim(skb, skb->len - 4);
total_rx_packets++;
/* eth type trans needs skb->data to point to something */
@@ -4057,14 +4279,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
}
}
- /* adjust length to remove Ethernet CRC, this must be
- * done after the TBI_ACCEPT workaround above */
- length -= 4;
-
- /* probably a little skewed due to removing CRC */
- total_rx_bytes += length;
+ total_rx_bytes += (length - 4); /* don't count FCS */
total_rx_packets++;
+ if (likely(!(netdev->features & NETIF_F_RXFCS)))
+ /* adjust length to remove Ethernet CRC, this must be
+ * done after the TBI_ACCEPT workaround above
+ */
+ length -= 4;
+
e1000_check_copybreak(netdev, buffer_info, length, &skb);
skb_put(skb, length);