From 99fe61b27774b5dcb06e77ab6a02ba26ebb1653c Mon Sep 17 00:00:00 2001 From: "Ben Dooks (Codethink)" Date: Wed, 18 Dec 2019 09:53:08 +0000 Subject: [PATCH 01/12] e1000e: fix missing cpu_to_le64 on buffer_addr The following warning suggests there is a missing cpu_to_le64() in the e1000_flush_tx_ring() function (it is also the behaviour elsewhere in the driver to do cpu_to_le64() on the buffer_addr when setting it) drivers/net/ethernet/intel/e1000e/netdev.c:3813:30: warning: incorrect type in assignment (different base types) drivers/net/ethernet/intel/e1000e/netdev.c:3813:30: expected restricted __le64 [usertype] buffer_addr drivers/net/ethernet/intel/e1000e/netdev.c:3813:30: got unsigned long long [usertype] dma Signed-off-by: Ben Dooks (Codethink) Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index db4ea58bac825..618c218978fe0 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3807,7 +3807,7 @@ static void e1000_flush_tx_ring(struct e1000_adapter *adapter) tdt = er32(TDT(0)); BUG_ON(tdt != tx_ring->next_to_use); tx_desc = E1000_TX_DESC(*tx_ring, tx_ring->next_to_use); - tx_desc->buffer_addr = tx_ring->dma; + tx_desc->buffer_addr = cpu_to_le64(tx_ring->dma); tx_desc->lower.data = cpu_to_le32(txd_lower | size); tx_desc->upper.data = 0; From 2e05f756c7099c8991142382648a37b0d4c85943 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 18 Dec 2019 22:16:56 +0800 Subject: [PATCH 02/12] net: intel: e1000e: fix possible sleep-in-atomic-context bugs in e1000e_get_hw_semaphore() The driver may sleep while holding a spinlock. The function call path (from bottom to top) in Linux 4.19 is: drivers/net/ethernet/intel/e1000e/mac.c, 1366: usleep_range in e1000e_get_hw_semaphore drivers/net/ethernet/intel/e1000e/80003es2lan.c, 322: e1000e_get_hw_semaphore in e1000_release_swfw_sync_80003es2lan drivers/net/ethernet/intel/e1000e/80003es2lan.c, 197: e1000_release_swfw_sync_80003es2lan in e1000_release_phy_80003es2lan drivers/net/ethernet/intel/e1000e/netdev.c, 4883: (FUNC_PTR) e1000_release_phy_80003es2lan in e1000e_update_phy_stats drivers/net/ethernet/intel/e1000e/netdev.c, 4917: e1000e_update_phy_stats in e1000e_update_stats drivers/net/ethernet/intel/e1000e/netdev.c, 5945: e1000e_update_stats in e1000e_get_stats64 drivers/net/ethernet/intel/e1000e/netdev.c, 5944: spin_lock in e1000e_get_stats64 drivers/net/ethernet/intel/e1000e/mac.c, 1384: usleep_range in e1000e_get_hw_semaphore drivers/net/ethernet/intel/e1000e/80003es2lan.c, 322: e1000e_get_hw_semaphore in e1000_release_swfw_sync_80003es2lan drivers/net/ethernet/intel/e1000e/80003es2lan.c, 197: e1000_release_swfw_sync_80003es2lan in e1000_release_phy_80003es2lan drivers/net/ethernet/intel/e1000e/netdev.c, 4883: (FUNC_PTR) e1000_release_phy_80003es2lan in e1000e_update_phy_stats drivers/net/ethernet/intel/e1000e/netdev.c, 4917: e1000e_update_phy_stats in e1000e_update_stats drivers/net/ethernet/intel/e1000e/netdev.c, 5945: e1000e_update_stats in e1000e_get_stats64 drivers/net/ethernet/intel/e1000e/netdev.c, 5944: spin_lock in e1000e_get_stats64 (FUNC_PTR) means a function pointer is called. To fix these bugs, usleep_range() is replaced with udelay(). These bugs are found by a static analysis tool STCheck written by myself. Signed-off-by: Jia-Ju Bai Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index e531976f8a677..51512a73fdd07 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -1363,7 +1363,7 @@ s32 e1000e_get_hw_semaphore(struct e1000_hw *hw) if (!(swsm & E1000_SWSM_SMBI)) break; - usleep_range(50, 100); + udelay(100); i++; } @@ -1381,7 +1381,7 @@ s32 e1000e_get_hw_semaphore(struct e1000_hw *hw) if (er32(SWSM) & E1000_SWSM_SWESMBI) break; - usleep_range(50, 100); + udelay(100); } if (i == timeout) { From 38db952b27d27f52c54c713cae487dd16a1c83af Mon Sep 17 00:00:00 2001 From: Chen Zhou Date: Wed, 8 Jan 2020 21:39:59 +0800 Subject: [PATCH 03/12] igc: make non-global functions static Fix sparse warning: drivers/net/ethernet/intel/igc/igc_ptp.c:512:6: warning: symbol 'igc_ptp_tx_work' was not declared. Should it be static? drivers/net/ethernet/intel/igc/igc_ptp.c:644:6: warning: symbol 'igc_ptp_suspend' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: Chen Zhou Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_ptp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 693506587198e..389a969fe5f4d 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -509,7 +509,7 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) * This work function polls the TSYNCTXCTL valid bit to determine when a * timestamp has been taken for the current stored skb. */ -void igc_ptp_tx_work(struct work_struct *work) +static void igc_ptp_tx_work(struct work_struct *work) { struct igc_adapter *adapter = container_of(work, struct igc_adapter, ptp_tx_work); @@ -641,7 +641,7 @@ void igc_ptp_init(struct igc_adapter *adapter) * This function stops the overflow check work and PTP Tx timestamp work, and * will prepare the device for OS suspend. */ -void igc_ptp_suspend(struct igc_adapter *adapter) +static void igc_ptp_suspend(struct igc_adapter *adapter) { if (!(adapter->ptp_flags & IGC_PTP_ENABLED)) return; From 8594a7f384ade8cd626da1c18d03ba01bf70d10e Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Mon, 13 Jan 2020 15:33:59 +0200 Subject: [PATCH 04/12] igc: Complete to commit Add legacy power management support commit 9513d2a5dc7f ("igc: Add legacy power management support") Add power management resume and schedule suspend requests. Add power management get and put synchronization. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_main.c | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index d9d5425fe8d99..5f30dcd1e2074 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -4029,6 +4029,9 @@ static void igc_watchdog_task(struct work_struct *work) } } if (link) { + /* Cancel scheduled suspend requests. */ + pm_runtime_resume(netdev->dev.parent); + if (!netif_carrier_ok(netdev)) { u32 ctrl; @@ -4114,6 +4117,8 @@ static void igc_watchdog_task(struct work_struct *work) return; } } + pm_schedule_suspend(netdev->dev.parent, + MSEC_PER_SEC * 5); /* also check for alternate media here */ } else if (!netif_carrier_ok(netdev) && @@ -4337,6 +4342,7 @@ static int igc_request_irq(struct igc_adapter *adapter) static int __igc_open(struct net_device *netdev, bool resuming) { struct igc_adapter *adapter = netdev_priv(netdev); + struct pci_dev *pdev = adapter->pdev; struct igc_hw *hw = &adapter->hw; int err = 0; int i = 0; @@ -4348,6 +4354,9 @@ static int __igc_open(struct net_device *netdev, bool resuming) return -EBUSY; } + if (!resuming) + pm_runtime_get_sync(&pdev->dev); + netif_carrier_off(netdev); /* allocate transmit descriptors */ @@ -4386,6 +4395,9 @@ static int __igc_open(struct net_device *netdev, bool resuming) rd32(IGC_ICR); igc_irq_enable(adapter); + if (!resuming) + pm_runtime_put(&pdev->dev); + netif_tx_start_all_queues(netdev); /* start the watchdog. */ @@ -4404,6 +4416,8 @@ static int __igc_open(struct net_device *netdev, bool resuming) igc_free_all_tx_resources(adapter); err_setup_tx: igc_reset(adapter); + if (!resuming) + pm_runtime_put(&pdev->dev); return err; } @@ -4428,9 +4442,13 @@ static int igc_open(struct net_device *netdev) static int __igc_close(struct net_device *netdev, bool suspending) { struct igc_adapter *adapter = netdev_priv(netdev); + struct pci_dev *pdev = adapter->pdev; WARN_ON(test_bit(__IGC_RESETTING, &adapter->state)); + if (!suspending) + pm_runtime_get_sync(&pdev->dev); + igc_down(adapter); igc_release_hw_control(adapter); @@ -4440,6 +4458,9 @@ static int __igc_close(struct net_device *netdev, bool suspending) igc_free_all_tx_resources(adapter); igc_free_all_rx_resources(adapter); + if (!suspending) + pm_runtime_put_sync(&pdev->dev); + return 0; } @@ -4792,6 +4813,10 @@ static int igc_probe(struct pci_dev *pdev, pcie_print_link_status(pdev); netdev_info(netdev, "MAC: %pM\n", netdev->dev_addr); + dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP); + + pm_runtime_put_noidle(&pdev->dev); + return 0; err_register: @@ -4826,6 +4851,8 @@ static void igc_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct igc_adapter *adapter = netdev_priv(netdev); + pm_runtime_get_noresume(&pdev->dev); + igc_ptp_stop(adapter); set_bit(__IGC_DOWN, &adapter->state); From 9c384ee31e8175bcea9057ecbbb20d5b1fc48c88 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Tue, 14 Jan 2020 09:55:54 +0200 Subject: [PATCH 05/12] igc: Add dump options Placeholder for debugging functionality. In this patch, we add some registers and rings summary dumps. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/Makefile | 2 +- drivers/net/ethernet/intel/igc/igc.h | 4 + drivers/net/ethernet/intel/igc/igc_defines.h | 3 + drivers/net/ethernet/intel/igc/igc_dump.c | 323 +++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_main.c | 2 + drivers/net/ethernet/intel/igc/igc_regs.h | 5 + 6 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/igc/igc_dump.c diff --git a/drivers/net/ethernet/intel/igc/Makefile b/drivers/net/ethernet/intel/igc/Makefile index 49fb1e1965cd5..e3c164c12e108 100644 --- a/drivers/net/ethernet/intel/igc/Makefile +++ b/drivers/net/ethernet/intel/igc/Makefile @@ -8,4 +8,4 @@ obj-$(CONFIG_IGC) += igc.o igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o \ -igc_ethtool.o igc_ptp.o +igc_ethtool.o igc_ptp.o igc_dump.o diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 52066bdbbad0a..5d38d0faecede 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -42,6 +42,10 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter, const u8 *addr, u8 queue, u8 flags); void igc_update_stats(struct igc_adapter *adapter); +/* igc_dump declarations */ +void igc_rings_dump(struct igc_adapter *adapter); +void igc_regs_dump(struct igc_adapter *adapter); + extern char igc_driver_name[]; extern char igc_driver_version[]; diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 58efa7a02c684..3c03962bde5e7 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -259,6 +259,9 @@ #define IGC_GPIE_EIAME 0x40000000 #define IGC_GPIE_PBA 0x80000000 +/* Receive Descriptor bit definitions */ +#define IGC_RXD_STAT_DD 0x01 /* Descriptor Done */ + /* Transmit Descriptor bit definitions */ #define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */ #define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */ diff --git a/drivers/net/ethernet/intel/igc/igc_dump.c b/drivers/net/ethernet/intel/igc/igc_dump.c new file mode 100644 index 0000000000000..657ab50ae2965 --- /dev/null +++ b/drivers/net/ethernet/intel/igc/igc_dump.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018 Intel Corporation */ + +#include "igc.h" + +struct igc_reg_info { + u32 ofs; + char *name; +}; + +static const struct igc_reg_info igc_reg_info_tbl[] = { + /* General Registers */ + {IGC_CTRL, "CTRL"}, + {IGC_STATUS, "STATUS"}, + {IGC_CTRL_EXT, "CTRL_EXT"}, + {IGC_MDIC, "MDIC"}, + + /* Interrupt Registers */ + {IGC_ICR, "ICR"}, + + /* RX Registers */ + {IGC_RCTL, "RCTL"}, + {IGC_RDLEN(0), "RDLEN"}, + {IGC_RDH(0), "RDH"}, + {IGC_RDT(0), "RDT"}, + {IGC_RXDCTL(0), "RXDCTL"}, + {IGC_RDBAL(0), "RDBAL"}, + {IGC_RDBAH(0), "RDBAH"}, + + /* TX Registers */ + {IGC_TCTL, "TCTL"}, + {IGC_TDBAL(0), "TDBAL"}, + {IGC_TDBAH(0), "TDBAH"}, + {IGC_TDLEN(0), "TDLEN"}, + {IGC_TDH(0), "TDH"}, + {IGC_TDT(0), "TDT"}, + {IGC_TXDCTL(0), "TXDCTL"}, + {IGC_TDFH, "TDFH"}, + {IGC_TDFT, "TDFT"}, + {IGC_TDFHS, "TDFHS"}, + {IGC_TDFPC, "TDFPC"}, + + /* List Terminator */ + {} +}; + +/* igc_regdump - register printout routine */ +static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo) +{ + int n = 0; + char rname[16]; + u32 regs[8]; + + switch (reginfo->ofs) { + case IGC_RDLEN(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDLEN(n)); + break; + case IGC_RDH(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDH(n)); + break; + case IGC_RDT(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDT(n)); + break; + case IGC_RXDCTL(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RXDCTL(n)); + break; + case IGC_RDBAL(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDBAL(n)); + break; + case IGC_RDBAH(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDBAH(n)); + break; + case IGC_TDBAL(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_RDBAL(n)); + break; + case IGC_TDBAH(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TDBAH(n)); + break; + case IGC_TDLEN(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TDLEN(n)); + break; + case IGC_TDH(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TDH(n)); + break; + case IGC_TDT(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TDT(n)); + break; + case IGC_TXDCTL(0): + for (n = 0; n < 4; n++) + regs[n] = rd32(IGC_TXDCTL(n)); + break; + default: + pr_info("%-15s %08x\n", reginfo->name, rd32(reginfo->ofs)); + return; + } + + snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]"); + pr_info("%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1], + regs[2], regs[3]); +} + +/* igc_rings_dump - Tx-rings and Rx-rings */ +void igc_rings_dump(struct igc_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct my_u0 { u64 a; u64 b; } *u0; + union igc_adv_tx_desc *tx_desc; + union igc_adv_rx_desc *rx_desc; + struct igc_ring *tx_ring; + struct igc_ring *rx_ring; + u32 staterr; + u16 i, n; + + if (!netif_msg_hw(adapter)) + return; + + /* Print netdevice Info */ + if (netdev) { + dev_info(&adapter->pdev->dev, "Net device Info\n"); + pr_info("Device Name state trans_start\n"); + pr_info("%-15s %016lX %016lX\n", netdev->name, + netdev->state, dev_trans_start(netdev)); + } + + /* Print TX Ring Summary */ + if (!netdev || !netif_running(netdev)) + goto exit; + + dev_info(&adapter->pdev->dev, "TX Rings Summary\n"); + pr_info("Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n"); + for (n = 0; n < adapter->num_tx_queues; n++) { + struct igc_tx_buffer *buffer_info; + + tx_ring = adapter->tx_ring[n]; + buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean]; + + pr_info(" %5d %5X %5X %016llX %04X %p %016llX\n", + n, tx_ring->next_to_use, tx_ring->next_to_clean, + (u64)dma_unmap_addr(buffer_info, dma), + dma_unmap_len(buffer_info, len), + buffer_info->next_to_watch, + (u64)buffer_info->time_stamp); + } + + /* Print TX Rings */ + if (!netif_msg_tx_done(adapter)) + goto rx_ring_summary; + + dev_info(&adapter->pdev->dev, "TX Rings Dump\n"); + + /* Transmit Descriptor Formats + * + * Advanced Transmit Descriptor + * +--------------------------------------------------------------+ + * 0 | Buffer Address [63:0] | + * +--------------------------------------------------------------+ + * 8 | PAYLEN | PORTS |CC|IDX | STA | DCMD |DTYP|MAC|RSV| DTALEN | + * +--------------------------------------------------------------+ + * 63 46 45 40 39 38 36 35 32 31 24 15 0 + */ + + for (n = 0; n < adapter->num_tx_queues; n++) { + tx_ring = adapter->tx_ring[n]; + pr_info("------------------------------------\n"); + pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index); + pr_info("------------------------------------\n"); + pr_info("T [desc] [address 63:0 ] [PlPOCIStDDM Ln] [bi->dma ] leng ntw timestamp bi->skb\n"); + + for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) { + const char *next_desc; + struct igc_tx_buffer *buffer_info; + + tx_desc = IGC_TX_DESC(tx_ring, i); + buffer_info = &tx_ring->tx_buffer_info[i]; + u0 = (struct my_u0 *)tx_desc; + if (i == tx_ring->next_to_use && + i == tx_ring->next_to_clean) + next_desc = " NTC/U"; + else if (i == tx_ring->next_to_use) + next_desc = " NTU"; + else if (i == tx_ring->next_to_clean) + next_desc = " NTC"; + else + next_desc = ""; + + pr_info("T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n", + i, le64_to_cpu(u0->a), + le64_to_cpu(u0->b), + (u64)dma_unmap_addr(buffer_info, dma), + dma_unmap_len(buffer_info, len), + buffer_info->next_to_watch, + (u64)buffer_info->time_stamp, + buffer_info->skb, next_desc); + + if (netif_msg_pktdata(adapter) && buffer_info->skb) + print_hex_dump(KERN_INFO, "", + DUMP_PREFIX_ADDRESS, + 16, 1, buffer_info->skb->data, + dma_unmap_len(buffer_info, len), + true); + } + } + + /* Print RX Rings Summary */ +rx_ring_summary: + dev_info(&adapter->pdev->dev, "RX Rings Summary\n"); + pr_info("Queue [NTU] [NTC]\n"); + for (n = 0; n < adapter->num_rx_queues; n++) { + rx_ring = adapter->rx_ring[n]; + pr_info(" %5d %5X %5X\n", + n, rx_ring->next_to_use, rx_ring->next_to_clean); + } + + /* Print RX Rings */ + if (!netif_msg_rx_status(adapter)) + goto exit; + + dev_info(&adapter->pdev->dev, "RX Rings Dump\n"); + + /* Advanced Receive Descriptor (Read) Format + * 63 1 0 + * +-----------------------------------------------------+ + * 0 | Packet Buffer Address [63:1] |A0/NSE| + * +----------------------------------------------+------+ + * 8 | Header Buffer Address [63:1] | DD | + * +-----------------------------------------------------+ + * + * + * Advanced Receive Descriptor (Write-Back) Format + * + * 63 48 47 32 31 30 21 20 17 16 4 3 0 + * +------------------------------------------------------+ + * 0 | Packet IP |SPH| HDR_LEN | RSV|Packet| RSS | + * | Checksum Ident | | | | Type | Type | + * +------------------------------------------------------+ + * 8 | VLAN Tag | Length | Extended Error | Extended Status | + * +------------------------------------------------------+ + * 63 48 47 32 31 20 19 0 + */ + + for (n = 0; n < adapter->num_rx_queues; n++) { + rx_ring = adapter->rx_ring[n]; + pr_info("------------------------------------\n"); + pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index); + pr_info("------------------------------------\n"); + pr_info("R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n"); + pr_info("RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n"); + + for (i = 0; i < rx_ring->count; i++) { + const char *next_desc; + struct igc_rx_buffer *buffer_info; + + buffer_info = &rx_ring->rx_buffer_info[i]; + rx_desc = IGC_RX_DESC(rx_ring, i); + u0 = (struct my_u0 *)rx_desc; + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + + if (i == rx_ring->next_to_use) + next_desc = " NTU"; + else if (i == rx_ring->next_to_clean) + next_desc = " NTC"; + else + next_desc = ""; + + if (staterr & IGC_RXD_STAT_DD) { + /* Descriptor Done */ + pr_info("%s[0x%03X] %016llX %016llX ---------------- %s\n", + "RWB", i, + le64_to_cpu(u0->a), + le64_to_cpu(u0->b), + next_desc); + } else { + pr_info("%s[0x%03X] %016llX %016llX %016llX %s\n", + "R ", i, + le64_to_cpu(u0->a), + le64_to_cpu(u0->b), + (u64)buffer_info->dma, + next_desc); + + if (netif_msg_pktdata(adapter) && + buffer_info->dma && buffer_info->page) { + print_hex_dump(KERN_INFO, "", + DUMP_PREFIX_ADDRESS, + 16, 1, + page_address + (buffer_info->page) + + buffer_info->page_offset, + igc_rx_bufsz(rx_ring), + true); + } + } + } + } + +exit: + return; +} + +/* igc_regs_dump - registers dump */ +void igc_regs_dump(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + struct igc_reg_info *reginfo; + + /* Print Registers */ + dev_info(&adapter->pdev->dev, "Register Dump\n"); + pr_info(" Register Name Value\n"); + for (reginfo = (struct igc_reg_info *)igc_reg_info_tbl; + reginfo->name; reginfo++) { + igc_regdump(hw, reginfo); + } +} diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 5f30dcd1e2074..3c748d2394237 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -3546,6 +3546,8 @@ static void igc_reset_task(struct work_struct *work) adapter = container_of(work, struct igc_adapter, reset_task); + igc_rings_dump(adapter); + igc_regs_dump(adapter); netdev_err(adapter->netdev, "Reset adapter\n"); igc_reinit_locked(adapter); } diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index c9029b549b908..d4af53a80f116 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -17,6 +17,11 @@ /* Internal Packet Buffer Size Registers */ #define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */ #define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */ +#define IGC_TDFH 0x03410 /* Tx Data FIFO Head - RW */ +#define IGC_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ +#define IGC_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ +#define IGC_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */ +#define IGC_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */ /* NVM Register Descriptions */ #define IGC_EERD 0x12014 /* EEprom mode read - RW */ From 59e466888038dcb84a402b4632c9ffa9dc48f533 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Sun, 19 Jan 2020 13:57:13 +0200 Subject: [PATCH 06/12] e1000e: Add support for Alder Lake Add devices ID's for the next LOM generations that will be available on the next Intel Client platform (Alder Lake) This patch provides the initial support for these devices Signed-off-by: Sasha Neftin Reviewed-by: Paul Menzel Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ethtool.c | 2 ++ drivers/net/ethernet/intel/e1000e/hw.h | 5 +++++ drivers/net/ethernet/intel/e1000e/ich8lan.c | 7 +++++++ drivers/net/ethernet/intel/e1000e/netdev.c | 6 ++++++ drivers/net/ethernet/intel/e1000e/ptp.c | 1 + 5 files changed, 21 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index adce7e319b9ea..9e7881db7859c 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -897,6 +897,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) case e1000_pch_cnp: /* fall through */ case e1000_pch_tgp: + case e1000_pch_adp: mask |= BIT(18); break; default: @@ -1561,6 +1562,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: fext_nvm11 = er32(FEXTNVM11); fext_nvm11 &= ~E1000_FEXTNVM11_DISABLE_MULR_FIX; ew32(FEXTNVM11, fext_nvm11); diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index f556163481cba..b89862129a75e 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -97,6 +97,10 @@ struct e1000_hw; #define E1000_DEV_ID_PCH_TGP_I219_LM14 0x15F9 #define E1000_DEV_ID_PCH_TGP_I219_V14 0x15FA #define E1000_DEV_ID_PCH_TGP_I219_LM15 0x15F4 +#define E1000_DEV_ID_PCH_ADP_I219_LM16 0x1A1E +#define E1000_DEV_ID_PCH_ADP_I219_V16 0x1A1F +#define E1000_DEV_ID_PCH_ADP_I219_LM17 0x1A1C +#define E1000_DEV_ID_PCH_ADP_I219_V17 0x1A1D #define E1000_REVISION_4 4 @@ -121,6 +125,7 @@ enum e1000_mac_type { e1000_pch_spt, e1000_pch_cnp, e1000_pch_tgp, + e1000_pch_adp, }; enum e1000_media_type { diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index b4135c50e9052..735bf25952fc7 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -317,6 +317,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: if (e1000_phy_is_accessible_pchlan(hw)) break; @@ -460,6 +461,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: /* In case the PHY needs to be in mdio slow mode, * set slow mode and try to get the PHY id again. */ @@ -703,6 +705,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: case e1000_pchlan: /* check management mode */ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; @@ -1642,6 +1645,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: rc = e1000_init_phy_params_pchlan(hw); break; default: @@ -2095,6 +2099,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; break; default: @@ -3133,6 +3138,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: bank1_offset = nvm->flash_bank_size; act_offset = E1000_ICH_NVM_SIG_WORD; @@ -4077,6 +4083,7 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: word = NVM_COMPAT; valid_csum_mask = NVM_COMPAT_VALID_CSUM; break; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 618c218978fe0..62236543e92d3 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3536,6 +3536,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) break; case e1000_pch_cnp: case e1000_pch_tgp: + case e1000_pch_adp: if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { /* Stable 24MHz frequency */ incperiod = INCPERIOD_24MHZ; @@ -4049,6 +4050,7 @@ void e1000e_reset(struct e1000_adapter *adapter) case e1000_pch_cnp: /* fall-through */ case e1000_pch_tgp: + case e1000_pch_adp: fc->refresh_time = 0xFFFF; fc->pause_time = 0xFFFF; @@ -7760,6 +7762,10 @@ static const struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM14), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_cnp }, { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */ }; diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index eaa5a0fb99f06..439fda2f5368f 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -297,6 +297,7 @@ void e1000e_ptp_init(struct e1000_adapter *adapter) case e1000_pch_cnp: /* fall-through */ case e1000_pch_tgp: + case e1000_pch_adp: if ((hw->mac.type < e1000_pch_lpt) || (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) { adapter->ptp_clock_info.max_adj = 24000000 - 1; From e7d0f4b3ad57bc44d378a8b252c670f0cbf219ee Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Mon, 20 Jan 2020 08:17:58 +0200 Subject: [PATCH 07/12] igc: Fix the typo in comment Fix the typo and comment to correspond to the i225 device Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 5d38d0faecede..cb1362188c2aa 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -112,7 +112,7 @@ extern char igc_driver_version[]; #define IGC_RX_HDR_LEN IGC_RXBUFFER_256 /* Transmit and receive latency (for PTP timestamps) */ -/* FIXME: These values were estimated using the ones that i210 has as +/* FIXME: These values were estimated using the ones that i225 has as * basis, they seem to provide good numbers with ptp4l/phc2sys, but we * need to confirm them. */ From 563212224b7e7b7da9a6903dc1a7a41f7e48ac51 Mon Sep 17 00:00:00 2001 From: Vitaly Lifshits Date: Tue, 21 Jan 2020 15:46:28 -0800 Subject: [PATCH 08/12] e1000e: Add support for Tiger Lake device Added support for a device id that is a part of the Intel Tiger Lake platform. Signed-off-by: Vitaly Lifshits Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/hw.h | 1 + drivers/net/ethernet/intel/e1000e/netdev.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index b89862129a75e..b1447221669e7 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -97,6 +97,7 @@ struct e1000_hw; #define E1000_DEV_ID_PCH_TGP_I219_LM14 0x15F9 #define E1000_DEV_ID_PCH_TGP_I219_V14 0x15FA #define E1000_DEV_ID_PCH_TGP_I219_LM15 0x15F4 +#define E1000_DEV_ID_PCH_TGP_I219_V15 0x15F5 #define E1000_DEV_ID_PCH_ADP_I219_LM16 0x1A1E #define E1000_DEV_ID_PCH_ADP_I219_V16 0x1A1F #define E1000_DEV_ID_PCH_ADP_I219_LM17 0x1A1C diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 62236543e92d3..fb92002cabee6 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -7762,6 +7762,7 @@ static const struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM14), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V15), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_cnp }, From a5136f7677a3bd47e3053a36b447259ec48fd1ed Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Wed, 22 Jan 2020 11:21:13 +0200 Subject: [PATCH 09/12] igc: Complete to commit Add basic skeleton for PTP commit 5f2958052c58 ("igc: Add basic skeleton for PTP") added basic support for PTP, what's missing is support for suspending. Legacy power management has been added. Now we can add the suspend method to the igc_shutdown. By cleaning the runtime storage for timestamp this avoids a possible invalid memory access when the system comes back from suspend state. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 1 + drivers/net/ethernet/intel/igc/igc_main.c | 2 ++ drivers/net/ethernet/intel/igc/igc_ptp.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index cb1362188c2aa..5e9c2dd8b8e44 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -556,6 +556,7 @@ int igc_erase_filter(struct igc_adapter *adapter, void igc_ptp_init(struct igc_adapter *adapter); void igc_ptp_reset(struct igc_adapter *adapter); +void igc_ptp_suspend(struct igc_adapter *adapter); void igc_ptp_stop(struct igc_adapter *adapter); void igc_ptp_rx_rgtstamp(struct igc_q_vector *q_vector, struct sk_buff *skb); void igc_ptp_rx_pktstamp(struct igc_q_vector *q_vector, void *va, diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 3c748d2394237..b805323e1be6a 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -4899,6 +4899,8 @@ static int __igc_shutdown(struct pci_dev *pdev, bool *enable_wake, if (netif_running(netdev)) __igc_close(netdev, true); + igc_ptp_suspend(adapter); + igc_clear_interrupt_scheme(adapter); rtnl_unlock(); diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 389a969fe5f4d..f99c514ad0f47 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -641,7 +641,7 @@ void igc_ptp_init(struct igc_adapter *adapter) * This function stops the overflow check work and PTP Tx timestamp work, and * will prepare the device for OS suspend. */ -static void igc_ptp_suspend(struct igc_adapter *adapter) +void igc_ptp_suspend(struct igc_adapter *adapter) { if (!(adapter->ptp_flags & IGC_PTP_ENABLED)) return; From bc23aa949aeba0b7a1341f24a1841eb175e01919 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Wed, 29 Jan 2020 16:30:07 +0200 Subject: [PATCH 10/12] igc: Add pcie error handler support Add pcie error detection, slot reset and resume capability Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_main.c | 103 ++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index b805323e1be6a..e982b5f54dc94 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -5076,6 +5076,108 @@ static void igc_shutdown(struct pci_dev *pdev) } } +/** + * igc_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current PCI connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + **/ +static pci_ers_result_t igc_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igc_adapter *adapter = netdev_priv(netdev); + + netif_device_detach(netdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + if (netif_running(netdev)) + igc_down(adapter); + pci_disable_device(pdev); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * igc_io_slot_reset - called after the PCI bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. Implementation + * resembles the first-half of the igc_resume routine. + **/ +static pci_ers_result_t igc_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + pci_ers_result_t result; + + if (pci_enable_device_mem(pdev)) { + dev_err(&pdev->dev, + "Could not re-enable PCI device after reset.\n"); + result = PCI_ERS_RESULT_DISCONNECT; + } else { + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + /* In case of PCI error, adapter loses its HW address + * so we should re-assign it here. + */ + hw->hw_addr = adapter->io_addr; + + igc_reset(adapter); + wr32(IGC_WUS, ~0); + result = PCI_ERS_RESULT_RECOVERED; + } + + return result; +} + +/** + * igc_io_resume - called when traffic can start to flow again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. Implementation resembles the + * second-half of the igc_resume routine. + */ +static void igc_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igc_adapter *adapter = netdev_priv(netdev); + + rtnl_lock(); + if (netif_running(netdev)) { + if (igc_open(netdev)) { + dev_err(&pdev->dev, "igc_open failed after reset\n"); + return; + } + } + + netif_device_attach(netdev); + + /* let the f/w know that the h/w is now under the control of the + * driver. + */ + igc_get_hw_control(adapter); + rtnl_unlock(); +} + +static const struct pci_error_handlers igc_err_handler = { + .error_detected = igc_io_error_detected, + .slot_reset = igc_io_slot_reset, + .resume = igc_io_resume, +}; + #ifdef CONFIG_PM static const struct dev_pm_ops igc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(igc_suspend, igc_resume) @@ -5093,6 +5195,7 @@ static struct pci_driver igc_driver = { .driver.pm = &igc_pm_ops, #endif .shutdown = igc_shutdown, + .err_handler = &igc_err_handler, }; /** From e055600dfbedc1c7fe44eff0c28b3061ab6123a2 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Mon, 3 Feb 2020 09:55:20 +0200 Subject: [PATCH 11/12] igc: Add WOL support This patch adds a define and WOL support for an i225 parts. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 1 + drivers/net/ethernet/intel/igc/igc_defines.h | 3 + drivers/net/ethernet/intel/igc/igc_ethtool.c | 61 ++++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_main.c | 10 ++++ 4 files changed, 75 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 5e9c2dd8b8e44..8d9ed4f0b69dc 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -61,6 +61,7 @@ extern char igc_driver_version[]; #define IGC_FLAG_QUEUE_PAIRS BIT(3) #define IGC_FLAG_DMAC BIT(4) #define IGC_FLAG_PTP BIT(8) +#define IGC_FLAG_WOL_SUPPORTED BIT(8) #define IGC_FLAG_NEED_LINK_UPDATE BIT(9) #define IGC_FLAG_MEDIA_RESET BIT(10) #define IGC_FLAG_MAS_ENABLE BIT(12) diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 3c03962bde5e7..4ddccccf42ccf 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -16,7 +16,10 @@ /* Wake Up Filter Control */ #define IGC_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define IGC_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define IGC_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ #define IGC_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define IGC_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ #define IGC_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */ diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index ee07011e13e9b..69f50b8e2af3b 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -308,6 +308,65 @@ static void igc_get_regs(struct net_device *netdev, regs_buff[168 + i] = rd32(IGC_TXDCTL(i)); } +static void igc_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + + wol->wolopts = 0; + + if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED)) + return; + + wol->supported = WAKE_UCAST | WAKE_MCAST | + WAKE_BCAST | WAKE_MAGIC | + WAKE_PHY; + + /* apply any specific unsupported masks here */ + switch (adapter->hw.device_id) { + default: + break; + } + + if (adapter->wol & IGC_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & IGC_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & IGC_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & IGC_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + if (adapter->wol & IGC_WUFC_LNKC) + wol->wolopts |= WAKE_PHY; +} + +static int igc_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_FILTER)) + return -EOPNOTSUPP; + + if (!(adapter->flags & IGC_FLAG_WOL_SUPPORTED)) + return wol->wolopts ? -EOPNOTSUPP : 0; + + /* these settings will always override what we currently have */ + adapter->wol = 0; + + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= IGC_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= IGC_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= IGC_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= IGC_WUFC_MAG; + if (wol->wolopts & WAKE_PHY) + adapter->wol |= IGC_WUFC_LNKC; + device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + + return 0; +} + static u32 igc_get_msglevel(struct net_device *netdev) { struct igc_adapter *adapter = netdev_priv(netdev); @@ -1859,6 +1918,8 @@ static const struct ethtool_ops igc_ethtool_ops = { .get_drvinfo = igc_get_drvinfo, .get_regs_len = igc_get_regs_len, .get_regs = igc_get_regs, + .get_wol = igc_get_wol, + .set_wol = igc_set_wol, .get_msglevel = igc_get_msglevel, .set_msglevel = igc_set_msglevel, .nway_reset = igc_nway_reset, diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index e982b5f54dc94..69fa1ce1f9271 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -4789,6 +4789,16 @@ static int igc_probe(struct pci_dev *pdev, hw->fc.requested_mode = igc_fc_default; hw->fc.current_mode = igc_fc_default; + /* By default, support wake on port A */ + adapter->flags |= IGC_FLAG_WOL_SUPPORTED; + + /* initialize the wol settings based on the eeprom settings */ + if (adapter->flags & IGC_FLAG_WOL_SUPPORTED) + adapter->wol |= IGC_WUFC_MAG; + + device_set_wakeup_enable(&adapter->pdev->dev, + adapter->flags & IGC_FLAG_WOL_SUPPORTED); + /* reset the hardware with the new settings */ igc_reset(adapter); From 67082b536a27299daeb3695571093b6771076d01 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Mon, 3 Feb 2020 10:11:50 +0200 Subject: [PATCH 12/12] igc: Add comment Separate interrupt and flag definitions. Made the code clear. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 8d9ed4f0b69dc..0014828eec46a 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -57,6 +57,8 @@ extern char igc_driver_version[]; /* Interrupt defines */ #define IGC_START_ITR 648 /* ~6000 ints/sec */ + +/* Flags definitions */ #define IGC_FLAG_HAS_MSI BIT(0) #define IGC_FLAG_QUEUE_PAIRS BIT(3) #define IGC_FLAG_DMAC BIT(4)