* [PATCH net-next 3/3] Add LAN743X to MAINTAINER list
From: Bryan.Whitehead @ 2017-08-11 19:48 UTC (permalink / raw)
To: netdev, davem; +Cc: UNGLinuxDriver
From: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Add LAN743X to MAINTAINER list
Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 2db0f8c..3216348 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8749,6 +8749,13 @@ F: drivers/net/dsa/microchip/*
F: include/linux/platform_data/microchip-ksz.h
F: Documentation/devicetree/bindings/net/dsa/ksz.txt
+MICROCHIP LAN743X ETHERNET DRIVER
+M: Bryan Whitehead <bryan.whitehead@microchip.com>
+M: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/microchip/lan743x.*
+
MICROCHIP USB251XB DRIVER
M: Richard Leitner <richard.leitner@skidata.com>
L: linux-usb@vger.kernel.org
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 2/3] Add LAN743X to Kconfig and Makefile
From: Bryan.Whitehead @ 2017-08-11 19:48 UTC (permalink / raw)
To: netdev, davem; +Cc: UNGLinuxDriver
From: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Add LAN743X Driver to Kconfig and Makefile
Removed "depends on SPI" from NET_VENDOR_MICROCHIP group
Because all existing drivers already specify SPI dependency, and
New driver does not have SPI dependency.
Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
drivers/net/ethernet/microchip/Kconfig | 10 +++++++++-
drivers/net/ethernet/microchip/Makefile | 1 +
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig
index 36a09d9..5796718 100644
--- a/drivers/net/ethernet/microchip/Kconfig
+++ b/drivers/net/ethernet/microchip/Kconfig
@@ -5,7 +5,6 @@
config NET_VENDOR_MICROCHIP
bool "Microchip devices"
default y
- depends on SPI
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -42,4 +41,13 @@ config ENCX24J600
To compile this driver as a module, choose M here. The module will be
called encx24j600.
+config LAN743X
+ tristate "LAN7430 support"
+ depends on PCI
+ ---help---
+ Support for the Microchip LAN7430 PCI Express Gigabit Ethernet chip
+
+ To compile this driver as a module, choose M here. The module will be
+ called lan743x.
+
endif # NET_VENDOR_MICROCHIP
diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index ff78f62..f7215dd 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_ENC28J60) += enc28j60.o
obj-$(CONFIG_ENCX24J600) += encx24j600.o encx24j600-regmap.o
+obj-$(CONFIG_LAN743X) += lan743x.o
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 1/3] Add LAN743X driver
From: Bryan.Whitehead @ 2017-08-11 19:47 UTC (permalink / raw)
To: netdev, davem; +Cc: UNGLinuxDriver
From: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Add Microchip LAN743X Driver files
LAN743X is a PCIe Gigabit ethernet adapter
Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
drivers/net/ethernet/microchip/lan743x.c | 6842 ++++++++++++++++++++++++++++++
drivers/net/ethernet/microchip/lan743x.h | 1417 +++++++
2 files changed, 8259 insertions(+)
create mode 100644 drivers/net/ethernet/microchip/lan743x.c
create mode 100644 drivers/net/ethernet/microchip/lan743x.h
diff --git a/drivers/net/ethernet/microchip/lan743x.c b/drivers/net/ethernet/microchip/lan743x.c
new file mode 100644
index 0000000..44d04ac
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x.c
@@ -0,0 +1,6842 @@
+/*
+ * Copyright (C) 2017 Microchip Technology
+ *
+ * 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 Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <linux/microchipphy.h>
+#include <linux/net_tstamp.h>
+#include <linux/phy.h>
+#include "lan743x.h"
+
+#define DRIVER_AUTHOR "Bryan Whitehead <Bryan.Whitehead@microchip.com>"
+#define DRIVER_DESC "LAN743x PCIe Gigabit Ethernet Driver"
+#define DRIVER_NAME "lan743x"
+#define DRIVER_VERSION "0.2.0.0"
+
+/* use ethtool to change the message enable for any given adapter */
+static int msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK |
+ NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
+module_param(msg_enable, int, 0000);
+MODULE_PARM_DESC(msg_enable, "Override default message enable");
+
+#define LAN743X_COMPONENT_FLAG_PCI BIT(0)
+#define LAN743X_COMPONENT_FLAG_CSR BIT(1)
+#define LAN743X_COMPONENT_FLAG_INTR BIT(2)
+#define LAN743X_COMPONENT_FLAG_DP BIT(3)
+#define LAN743X_COMPONENT_FLAG_GPIO BIT(4)
+#define LAN743X_COMPONENT_FLAG_MAC BIT(5)
+#define LAN743X_COMPONENT_FLAG_PHY BIT(6)
+#define LAN743X_COMPONENT_FLAG_PTP BIT(7)
+#define LAN743X_COMPONENT_FLAG_RFE BIT(8)
+#define LAN743X_COMPONENT_FLAG_FCT BIT(9)
+#define LAN743X_COMPONENT_FLAG_DMAC BIT(10)
+#define LAN743X_COMPONENT_FLAG_TX(channel) BIT(16 + (channel))
+#define LAN743X_COMPONENT_FLAG_RX(channel) BIT(20 + (channel))
+
+#define LAN743X_INIT_FLAG_NETDEV_REGISTERED BIT(24)
+
+/* PCI */
+#define INIT_FLAG_PCI_DEVICE_ENABLED BIT(0)
+#define INIT_FLAG_PCI_REGIONS_REQUESTED BIT(1)
+#define INIT_FLAG_CSR_MAPPED BIT(2)
+
+static int lan743x_pci_init(struct lan743x_adapter *adapter,
+ struct pci_dev *pdev)
+{
+ int ret = -ENODEV;
+ int bars = 0;
+ struct lan743x_pci *pci = &adapter->pci;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, pdev);
+ memset(pci, 0, sizeof(struct lan743x_pci));
+ pci->pdev = pdev;
+
+ ret = pci_enable_device_mem(pdev);
+ if (ret) {
+ NETIF_WARNING(adapter, probe, adapter->netdev,
+ "failed pci_enable_device_mem, ret = %d", ret);
+ goto clean_up;
+ }
+ pci->init_flags |= INIT_FLAG_PCI_DEVICE_ENABLED;
+
+ if (pdev->vendor != PCI_VENDOR_ID_SMSC) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "Unsupported Vendor ID, 0x%04X,", pdev->vendor);
+ ret = -ENODEV;
+ goto clean_up;
+ }
+
+ if (pdev->device != PCI_DEVICE_ID_SMSC_LAN7430) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "Unsupported Device ID, 0x%04X", pdev->device);
+ ret = -ENODEV;
+ goto clean_up;
+ }
+
+ NETIF_INFO(adapter, probe, adapter->netdev,
+ "PCI: Vendor ID = 0x%04X, Device ID = 0x%04X",
+ pdev->vendor, pdev->device);
+
+ bars = pci_select_bars(pdev, IORESOURCE_MEM);
+ ret = pci_request_selected_regions(pdev, bars, DRIVER_NAME);
+ if (ret) {
+ NETIF_WARNING(adapter, probe, adapter->netdev,
+ "failed pci_request_selected_Regions, ret = %d",
+ ret);
+ goto clean_up;
+ }
+ pci->init_flags |= INIT_FLAG_PCI_REGIONS_REQUESTED;
+ pci->bar_flags = bars;
+
+ pci_set_master(pdev);
+
+clean_up:
+ if (ret) {
+ NETIF_WARNING(adapter, probe, adapter->netdev,
+ "pci init failed, performing cleanup");
+ lan743x_pci_cleanup(adapter);
+ }
+ return ret;
+}
+
+static void lan743x_pci_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_pci *pci = &adapter->pci;
+
+ if (pci->init_flags & INIT_FLAG_PCI_REGIONS_REQUESTED) {
+ pci_release_selected_regions(pci->pdev,
+ pci_select_bars(
+ pci->pdev, IORESOURCE_MEM));
+ pci->init_flags &= ~INIT_FLAG_PCI_REGIONS_REQUESTED;
+ }
+
+ if (pci->init_flags & INIT_FLAG_PCI_DEVICE_ENABLED) {
+ pci_disable_device(pci->pdev);
+ pci->init_flags &= ~INIT_FLAG_PCI_DEVICE_ENABLED;
+ }
+
+ memset(pci, 0, sizeof(struct lan743x_pci));
+}
+
+static u8 __iomem *lan743x_pci_get_bar_address(struct lan743x_adapter *adapter,
+ int bar_index)
+{
+ u8 __iomem *result = NULL;
+ struct lan743x_pci *pci = &adapter->pci;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (bar_index >= 0) && (bar_index < 6));
+
+ if (test_bit(bar_index, &pci->bar_flags)) {
+ resource_size_t bar_start, bar_length;
+
+ bar_start = pci_resource_start(pci->pdev, bar_index);
+ bar_length = pci_resource_len(pci->pdev, bar_index);
+ result = ioremap(bar_start, bar_length);
+ }
+
+ return result;
+}
+
+static void lan743x_pci_release_bar_address(struct lan743x_adapter *adapter,
+ int bar_index,
+ u8 __iomem *bar_address)
+{
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (bar_index >= 0) && (bar_index < 6));
+ NETIF_ASSERT(adapter, drv, adapter->netdev, bar_address);
+
+ iounmap(bar_address);
+}
+
+static unsigned int lan743x_pci_get_irq(struct lan743x_adapter *adapter)
+{
+ struct lan743x_pci *pci = &adapter->pci;
+
+ return pci->pdev->irq;
+}
+
+/* CSR */
+static int lan743x_csr_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_csr *csr = &adapter->csr;
+ int result = -ENOMEM;
+ int supported = 0;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, csr);
+ memset(csr, 0, sizeof(struct lan743x_csr));
+
+ csr->csr_address = lan743x_pci_get_bar_address(adapter, 0);
+ if (!csr->csr_address) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "failed to get csr_address");
+ result = -ENOMEM;
+ goto clean_up;
+ }
+
+ csr->id_rev = lan743x_csr_read(adapter, ID_REV);
+ csr->fpga_rev = lan743x_csr_read(adapter, FPGA_REV);
+
+ NETIF_INFO(adapter, probe, adapter->netdev,
+ "ID_REV = 0x%08X, FPGA_REV = %d.%d",
+ csr->id_rev, (csr->fpga_rev) & 0x000000FF,
+ ((csr->fpga_rev) >> 8) & 0x000000FF);
+
+ if ((csr->id_rev & 0xFFFF0000) == 0x74300000)
+ supported = 1;
+
+ if (!supported) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "unsupported adapter, ID_REV = 0x%08X",
+ csr->id_rev);
+ result = -ENODEV;
+ goto clean_up;
+ }
+
+ result = lan743x_csr_light_reset(adapter);
+ if (result) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "light reset failed");
+ goto clean_up;
+ }
+
+ result = 0;
+
+clean_up:
+ if (result)
+ lan743x_csr_cleanup(adapter);
+ return result;
+}
+
+static void lan743x_csr_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_csr *csr = &adapter->csr;
+
+ if (csr->csr_address)
+ lan743x_pci_release_bar_address(adapter, 0, csr->csr_address);
+
+ memset(csr, 0, sizeof(struct lan743x_csr));
+}
+
+static int lan743x_csr_light_reset(struct lan743x_adapter *adapter)
+{
+ int result = -EIO;
+ u32 data;
+ unsigned long timeout;
+
+ data = lan743x_csr_read(adapter, HW_CFG);
+ data |= HW_CFG_LRST_;
+ lan743x_csr_write(adapter, HW_CFG, data);
+
+ timeout = jiffies + (10 * HZ);
+ do {
+ if (time_after(jiffies, timeout)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "timeout, incomplete soft reset");
+ result = -EIO;
+ goto done;
+ }
+ msleep(100);
+ data = lan743x_csr_read(adapter, HW_CFG);
+ } while (data & HW_CFG_LRST_);
+ result = 0;
+done:
+ return result;
+}
+
+static inline u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset)
+{
+ return ioread32(&adapter->csr.csr_address[offset]);
+}
+
+static inline void lan743x_csr_write(
+ struct lan743x_adapter *adapter, int offset, u32 data)
+{
+ iowrite32(data, &adapter->csr.csr_address[offset]);
+}
+
+/* INTERRUPTS */
+#define INTR_FLAG_IRQ_REQUESTED(vector_index) BIT(0 + vector_index)
+#define INTR_FLAG_MSI_ENABLED BIT(8)
+#define INTR_FLAG_MSIX_ENABLED BIT(9)
+#define INTR_FLAG_OPENED BIT(10)
+
+static void lan743x_vector_init(struct lan743x_vector *vector,
+ struct lan743x_adapter *adapter,
+ int vector_index, int irq, u32 int_mask,
+ lan743x_vector_handler handler, void *context)
+{
+ NETIF_ASSERT(adapter, probe, adapter->netdev, vector);
+ NETIF_ASSERT(adapter, probe, adapter->netdev, adapter);
+ NETIF_ASSERT(adapter, probe, adapter->netdev, int_mask);
+ NETIF_ASSERT(adapter, probe, adapter->netdev, handler);
+
+ memset(vector, 0, sizeof(struct lan743x_vector));
+
+ vector->adapter = adapter;
+ vector->vector_index = vector_index;
+ vector->irq = irq;
+ vector->int_mask = int_mask;
+ vector->handler = handler;
+ vector->context = context;
+}
+
+static void lan743x_intr_software_isr(void *context)
+{
+ struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+ struct lan743x_intr *intr = &adapter->intr;
+ u32 int_sts;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+
+ int_sts = lan743x_csr_read(adapter, INT_STS);
+ if (int_sts & INT_BIT_SW_GP_) {
+ lan743x_csr_write(adapter, INT_STS, INT_BIT_SW_GP_);
+
+ intr->software_isr_flag = 1;
+ }
+}
+
+static void lan743x_intr_other_isr(void *context, u32 int_sts)
+{
+ struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+
+ if (int_sts & INT_BIT_ALL_OTHER_) {
+ if (int_sts & INT_BIT_SW_GP_) {
+ lan743x_intr_software_isr(adapter);
+ int_sts &= ~INT_BIT_SW_GP_;
+ }
+ if (int_sts & INT_BIT_1588_) {
+ lan743x_ptp_isr(adapter);
+ int_sts &= ~INT_BIT_1588_;
+ }
+ if (int_sts & INT_BIT_MAC_) {
+ lan743x_mac_isr(adapter);
+ int_sts &= ~INT_BIT_MAC_;
+ }
+ if (int_sts & INT_BIT_FCT_) {
+ lan743x_fct_isr(adapter);
+ int_sts &= ~INT_BIT_FCT_;
+ }
+ if (int_sts & INT_BIT_DMA_GEN_) {
+ lan743x_dmac_isr(adapter);
+ int_sts &= ~INT_BIT_DMA_GEN_;
+ }
+ }
+ if (int_sts) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "unhandled interrupt, int_sts = 0x%08X", int_sts);
+ lan743x_csr_write(adapter, INT_EN_CLR, int_sts);
+ }
+}
+
+static void lan743x_intr_union_isr(void *context, u32 int_sts)
+{
+ struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+ int channel;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+
+ if (int_sts & INT_BIT_ALL_RX_) {
+ for (channel = 0; channel < LAN743X_NUMBER_OF_RX_CHANNELS;
+ channel++) {
+ u32 int_bit = INT_BIT_DMA_RX_(channel);
+
+ if (int_sts & int_bit) {
+ lan743x_rx_isr(&adapter->rx[channel],
+ int_bit);
+ int_sts &= ~int_bit;
+ }
+ }
+ }
+ if (int_sts & INT_BIT_ALL_TX_) {
+ for (channel = 0; channel < LAN743X_NUMBER_OF_TX_CHANNELS;
+ channel++) {
+ u32 int_bit = INT_BIT_DMA_TX_(channel);
+
+ if (int_sts & int_bit) {
+ lan743x_tx_isr(&adapter->tx[channel],
+ int_bit);
+ int_sts &= ~int_bit;
+ }
+ }
+ }
+ if (int_sts & INT_BIT_ALL_OTHER_) {
+ lan743x_intr_other_isr(adapter, int_sts & INT_BIT_ALL_OTHER_);
+ int_sts &= ~INT_BIT_ALL_OTHER_;
+ }
+ if (int_sts) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "unhandled interrupt, int_sts = 0x%08X", int_sts);
+ lan743x_csr_write(adapter, INT_EN_CLR, int_sts);
+ }
+}
+
+static irqreturn_t lan743x_vector_isr(int irq, void *ptr)
+{
+ irqreturn_t result = IRQ_NONE;
+ struct lan743x_vector *vector = (struct lan743x_vector *)ptr;
+ struct lan743x_adapter *adapter = NULL;
+ u32 int_sts;
+ u32 mask;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, vector);
+ adapter = vector->adapter;
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+
+ int_sts = lan743x_csr_read(adapter, INT_STS);
+ if (!(int_sts & INT_BIT_MAS_))
+ goto irq_done;
+
+ if (adapter->intr.number_of_vectors > 1) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ vector->vector_index >= 0);
+ /* disable vector interrupt */
+ lan743x_csr_write(adapter,
+ INT_VEC_EN_CLR,
+ INT_VEC_EN_(vector->vector_index));
+ } else {
+ /* disable master interrupt */
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_);
+ }
+
+ mask = lan743x_csr_read(adapter, INT_EN_SET);
+ int_sts &= mask;
+
+ int_sts &= (vector->int_mask);
+
+ if (int_sts) {
+ if (vector->handler) {
+ vector->handler(vector->context, int_sts);
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "vector->handler == NULL");
+ /* disable interrupts on this vector */
+ lan743x_csr_write(adapter, INT_EN_CLR,
+ vector->int_mask);
+ }
+ result = IRQ_HANDLED;
+ }
+
+ if (adapter->intr.number_of_vectors > 1) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ vector->vector_index >= 0);
+ /* enable vector interrupt */
+ lan743x_csr_write(adapter,
+ INT_VEC_EN_SET,
+ INT_VEC_EN_(vector->vector_index));
+ } else {
+ /* enable master interrupt */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
+ }
+
+irq_done:
+ return result;
+}
+
+static int lan743x_intr_test_isr(struct lan743x_adapter *adapter)
+{
+ struct lan743x_intr *intr = &adapter->intr;
+ int result = -ENODEV;
+ int timeout = 10;
+
+ intr->software_isr_flag = 0;
+
+ /* enable interrupt */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_SW_GP_);
+
+ /* activate interrupt here */
+ lan743x_csr_write(adapter, INT_SET, INT_BIT_SW_GP_);
+
+ while ((timeout > 0) && (!(intr->software_isr_flag))) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (intr->software_isr_flag) {
+ result = 0;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "timed out while waiting for test interrupt");
+ }
+
+ /* disable interrupts */
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_);
+
+ return result;
+}
+
+static int lan743x_intr_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_intr *intr = &adapter->intr;
+
+ memset(intr, 0, sizeof(struct lan743x_intr));
+
+ intr->irq = lan743x_pci_get_irq(adapter);
+
+ lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
+
+ return 0;
+}
+
+static void lan743x_intr_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_intr *intr = &adapter->intr;
+
+ lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
+
+ memset(intr, 0, sizeof(struct lan743x_intr));
+}
+
+static int lan743x_intr_open(struct lan743x_adapter *adapter)
+{
+ int ret = -ENODEV;
+ struct lan743x_intr *intr = &adapter->intr;
+ int index = 0;
+
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ !(intr->flags & INTR_FLAG_OPENED));
+
+ intr->number_of_vectors = 0;
+
+ memset(&intr->msix_entries[0], 0,
+ sizeof(struct msix_entry) * LAN743X_MAX_VECTOR_COUNT);
+ for (index = 0; index < LAN743X_MAX_VECTOR_COUNT; index++)
+ intr->msix_entries[index].entry = index;
+
+ ret = pci_enable_msix_range(adapter->pci.pdev,
+ intr->msix_entries,
+ LAN743X_MAX_VECTOR_COUNT,
+ LAN743X_MAX_VECTOR_COUNT);
+ if (ret > 0) {
+ intr->flags |= INTR_FLAG_MSIX_ENABLED;
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "Using MSIX interrupt mode");
+ if (ret == LAN743X_MAX_VECTOR_COUNT) {
+ lan743x_vector_init(&intr->vector_list[0], adapter,
+ 0, intr->msix_entries[0].vector,
+ INT_BIT_DMA_RX_(0),
+ lan743x_rx_isr, &adapter->rx[0]);
+
+ ret = request_irq(intr->vector_list[0].irq,
+ lan743x_vector_isr, 0,
+ DRIVER_NAME,
+ &intr->vector_list[0]);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "request_irq failed, ret = %d",
+ ret);
+ goto clean_up;
+ }
+ intr->flags |= INTR_FLAG_IRQ_REQUESTED(0);
+
+ lan743x_vector_init(&intr->vector_list[4], adapter,
+ 4, intr->msix_entries[4].vector,
+ INT_BIT_DMA_TX_(0),
+ lan743x_tx_isr, &adapter->tx[0]);
+
+ ret = request_irq(intr->vector_list[4].irq,
+ lan743x_vector_isr, 0,
+ DRIVER_NAME,
+ &intr->vector_list[4]);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "request_irq failed, ret = %d",
+ ret);
+ goto clean_up;
+ }
+ intr->flags |= INTR_FLAG_IRQ_REQUESTED(4);
+
+ lan743x_vector_init(&intr->vector_list[5], adapter,
+ 5, intr->msix_entries[5].vector,
+ INT_BIT_ALL_OTHER_,
+ lan743x_intr_other_isr, adapter);
+
+ ret = request_irq(intr->vector_list[5].irq,
+ lan743x_vector_isr, 0,
+ DRIVER_NAME,
+ &intr->vector_list[5]);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "request_irq failed, ret = %d",
+ ret);
+ goto clean_up;
+ }
+ intr->flags |= INTR_FLAG_IRQ_REQUESTED(5);
+ intr->number_of_vectors = 3;
+
+ /* map all interrupts */
+ lan743x_csr_write(adapter, INT_VEC_MAP0, 0);
+ lan743x_csr_write(adapter, INT_VEC_MAP1, 4);
+ lan743x_csr_write(adapter, INT_VEC_MAP2, 0x00555555);
+
+ /* enable vector 0, 4, 5 */
+ lan743x_csr_write(adapter, INT_VEC_EN_SET,
+ INT_VEC_EN_(0));
+ lan743x_csr_write(adapter, INT_VEC_EN_SET,
+ INT_VEC_EN_(4));
+ lan743x_csr_write(adapter, INT_VEC_EN_SET,
+ INT_VEC_EN_(5));
+
+ /* enable interrupts */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
+
+ ret = lan743x_intr_test_isr(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "ISR test failed, irq = %d",
+ intr->vector_list[5].irq);
+ goto clean_up;
+ } else {
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "irq = %d, passed ISR Test",
+ intr->vector_list[5].irq);
+ }
+ } else {
+ if (ret != LAN743X_MAX_VECTOR_COUNT) {
+ NETIF_WARNING(adapter, ifup, adapter->netdev,
+ "pci_enable_msix_range returned %d, but requested %d MSIX vectors",
+ ret, LAN743X_MAX_VECTOR_COUNT);
+ NETIF_WARNING(adapter, ifup, adapter->netdev,
+ "Will use only 1 MSIX vector instead");
+ }
+
+ lan743x_vector_init(&intr->vector_list[0], adapter,
+ 0, intr->msix_entries[0].vector,
+ INT_BIT_ALL_RX_ | INT_BIT_ALL_TX_ |
+ INT_BIT_ALL_OTHER_,
+ lan743x_intr_union_isr, adapter);
+
+ ret = request_irq(intr->vector_list[0].irq,
+ lan743x_vector_isr, 0,
+ DRIVER_NAME,
+ &intr->vector_list[0]);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "request_irq failed, ret = %d",
+ ret);
+ goto clean_up;
+ }
+ intr->flags |= INTR_FLAG_IRQ_REQUESTED(0);
+ intr->number_of_vectors = 1;
+
+ /* map all interrupts to vector 0 */
+ lan743x_csr_write(adapter, INT_VEC_MAP0, 0);
+ lan743x_csr_write(adapter, INT_VEC_MAP1, 0);
+ lan743x_csr_write(adapter, INT_VEC_MAP2, 0);
+
+ /* enable vector 0 */
+ lan743x_csr_write(adapter, INT_VEC_EN_SET,
+ INT_VEC_EN_(0));
+
+ /* enable interrupts */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
+
+ ret = lan743x_intr_test_isr(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "ISR test failed, irq = %d",
+ intr->vector_list[0].irq);
+ goto clean_up;
+ } else {
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "irq = %d, passed ISR Test",
+ intr->vector_list[0].irq);
+ }
+ }
+ } else if (!pci_enable_msi(adapter->pci.pdev)) {
+ intr->flags |= INTR_FLAG_MSI_ENABLED;
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "Using MSI interrupt mode");
+
+ lan743x_vector_init(&intr->vector_list[0], adapter,
+ 0, adapter->pci.pdev->irq,
+ INT_BIT_ALL_RX_ | INT_BIT_ALL_TX_ |
+ INT_BIT_ALL_OTHER_,
+ lan743x_intr_union_isr, adapter);
+
+ ret = request_irq(intr->vector_list[0].irq, lan743x_vector_isr,
+ 0, DRIVER_NAME, &intr->vector_list[0]);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "request_irq failed, ret = %d", ret);
+ goto clean_up;
+ }
+ intr->flags |= INTR_FLAG_IRQ_REQUESTED(0);
+ intr->number_of_vectors = 1;
+
+ /* map all interrupts to vector 0 */
+ lan743x_csr_write(adapter, INT_VEC_MAP0, 0);
+ lan743x_csr_write(adapter, INT_VEC_MAP1, 0);
+ lan743x_csr_write(adapter, INT_VEC_MAP2, 0);
+
+ /* enable vector 0 */
+ lan743x_csr_write(adapter, INT_VEC_EN_SET, INT_VEC_EN_(0));
+
+ /* enable interrupts */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
+
+ ret = lan743x_intr_test_isr(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "ISR test failed, irq = %d",
+ intr->vector_list[0].irq);
+ goto clean_up;
+ } else {
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "irq = %d, passed ISR Test",
+ intr->vector_list[0].irq);
+ }
+ } else {
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "Using legacy interrupt mode");
+
+ lan743x_vector_init(&intr->vector_list[0], adapter,
+ -1, intr->irq,
+ INT_BIT_ALL_RX_ | INT_BIT_ALL_TX_ |
+ INT_BIT_ALL_OTHER_,
+ lan743x_intr_union_isr, adapter);
+
+ ret = request_irq(intr->vector_list[0].irq, lan743x_vector_isr,
+ IRQF_SHARED, DRIVER_NAME,
+ &intr->vector_list[0]);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "request_irq failed, ret = %d", ret);
+ goto clean_up;
+ }
+ intr->flags |= INTR_FLAG_IRQ_REQUESTED(0);
+ intr->number_of_vectors = 1;
+
+ /* enable interrupts */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
+
+ ret = lan743x_intr_test_isr(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "ISR test failed, irq = %d",
+ intr->vector_list[0].irq);
+ goto clean_up;
+ } else {
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "irq = %d, passed ISR Test",
+ intr->vector_list[0].irq);
+ }
+ }
+
+ intr->flags |= INTR_FLAG_OPENED;
+ ret = 0;
+
+clean_up:
+ if (ret)
+ lan743x_intr_close(adapter);
+ return ret;
+}
+
+static void lan743x_intr_close(struct lan743x_adapter *adapter)
+{
+ struct lan743x_intr *intr = &adapter->intr;
+ int index = 0;
+
+ intr->flags &= ~INTR_FLAG_OPENED;
+
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_);
+ lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0x000000FF);
+
+ for (index = 0; index < LAN743X_MAX_VECTOR_COUNT; index++) {
+ if ((intr->flags) & INTR_FLAG_IRQ_REQUESTED(index)) {
+ free_irq(intr->vector_list[index].irq,
+ &intr->vector_list[index]);
+ intr->flags &= ~INTR_FLAG_IRQ_REQUESTED(index);
+ }
+ }
+ if ((intr->flags) & INTR_FLAG_MSI_ENABLED) {
+ pci_disable_msi(adapter->pci.pdev);
+ intr->flags &= ~INTR_FLAG_MSI_ENABLED;
+ }
+ if ((intr->flags) & INTR_FLAG_MSIX_ENABLED) {
+ pci_disable_msix(adapter->pci.pdev);
+ intr->flags &= ~INTR_FLAG_MSIX_ENABLED;
+ }
+}
+
+/* DP */
+static int lan743x_dp_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_dp *dp = &adapter->dp;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, dp);
+ memset(dp, 0, sizeof(*dp));
+
+ mutex_init(&dp->lock);
+
+ return 0;
+}
+
+static void lan743x_dp_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_dp *dp = &adapter->dp;
+
+ memset(dp, 0, sizeof(*dp));
+}
+
+static int lan743x_dp_open(struct lan743x_adapter *adapter)
+{
+ /* This empty function is kept as a place holder */
+ return 0;
+}
+
+static void lan743x_dp_close(struct lan743x_adapter *adapter)
+{
+ /* This empty function is kept as a place holder */
+}
+
+static int lan743x_dp_wait_till_not_busy(struct lan743x_adapter *adapter)
+{
+ int i;
+ u32 dp_sel = 0;
+
+ for (i = 0; i < 100; i++) {
+ dp_sel = lan743x_csr_read(adapter, DP_SEL);
+ if (dp_sel & DP_SEL_DPRDY_)
+ return 0;
+ usleep_range(40, 100);
+ }
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for data port not busy");
+ return -EIO;
+}
+
+static int lan743x_dp_write(struct lan743x_adapter *adapter,
+ u32 select, u32 addr, u32 length, u32 *buf)
+{
+ struct lan743x_dp *dp = &adapter->dp;
+ int ret = -EIO;
+ int i;
+ u32 dp_sel;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, buf);
+
+ mutex_lock(&dp->lock);
+
+ if (lan743x_dp_wait_till_not_busy(adapter))
+ goto done;
+
+ dp_sel = lan743x_csr_read(adapter, DP_SEL);
+ dp_sel &= ~DP_SEL_MASK_;
+ dp_sel |= select;
+ lan743x_csr_write(adapter, DP_SEL, dp_sel);
+
+ for (i = 0; i < length; i++) {
+ lan743x_csr_write(adapter, DP_ADDR, addr + i);
+ lan743x_csr_write(adapter, DP_DATA_0, buf[i]);
+ lan743x_csr_write(adapter, DP_CMD, DP_CMD_WRITE_);
+ if (lan743x_dp_wait_till_not_busy(adapter))
+ goto done;
+ }
+ ret = 0;
+
+done:
+ mutex_unlock(&dp->lock);
+ return ret;
+}
+
+static int lan743x_dp_write_hash_filter(struct lan743x_adapter *adapter,
+ u32 *hash_data)
+{
+ NETIF_ASSERT(adapter, drv, adapter->netdev, hash_data);
+
+ return lan743x_dp_write(adapter, DP_SEL_RFE_RAM,
+ DP_SEL_VHF_VLAN_LEN,
+ DP_SEL_VHF_HASH_LEN, hash_data);
+}
+
+/* GPIO */
+#define LAN743X_NUMBER_OF_GPIO (12)
+
+static int lan743x_gpio_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_gpio *gpio = &adapter->gpio;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, gpio);
+ memset(gpio, 0, sizeof(*gpio));
+
+ spin_lock_init(&gpio->gpio_lock);
+
+ gpio->gpio_cfg0 = 0; /* set all direction to input, data = 0 */
+ gpio->gpio_cfg1 = 0x0FFF0000;/* disable all gpio, set to open drain */
+ gpio->gpio_cfg2 = 0;/* set all to 1588 low polarity level */
+ gpio->gpio_cfg3 = 0;/* disable all 1588 output */
+ lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+ lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+ lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
+ lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
+
+ return 0;
+}
+
+static void lan743x_gpio_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_gpio *gpio = &adapter->gpio;
+
+ memset(gpio, 0, sizeof(*gpio));
+}
+
+static int lan743x_gpio_open(struct lan743x_adapter *adapter)
+{
+ /* This empty function is kept as a place holder */
+ return 0;
+}
+
+static void lan743x_gpio_close(struct lan743x_adapter *adapter)
+{
+ /* This empty function is kept as a place holder */
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_gpio_reserve_ptp_output(struct lan743x_adapter *adapter,
+ int bit, int ptp_channel)
+{
+ struct lan743x_gpio *gpio = &adapter->gpio;
+ int ret = -EBUSY;
+ unsigned long irq_flags = 0;
+ int bit_mask = BIT(bit);
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (bit >= 0) && (bit < LAN743X_NUMBER_OF_GPIO));
+ spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
+
+ if (!((gpio->used_bits) & bit_mask)) {
+ gpio->used_bits |= bit_mask;
+ gpio->output_bits |= bit_mask;
+ gpio->ptp_bits |= bit_mask;
+
+ /* set as output, and zero initial value */
+ gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_(bit);
+ gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_(bit);
+ lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+
+ /* enable gpio , and set buffer type to push pull */
+ gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_(bit);
+ gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_(bit);
+ lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+
+ /* set 1588 polarity to high */
+ gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_(bit);
+ lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
+
+ if (!ptp_channel) {
+ /* use channel A */
+ gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_(bit);
+ } else {
+ /* use channel B */
+ gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_(bit);
+ }
+ gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_(bit);
+ lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
+
+ ret = bit;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "GPIO %d is already in use", bit);
+ }
+ spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
+ return ret;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_gpio_release(struct lan743x_adapter *adapter, int bit)
+{
+ struct lan743x_gpio *gpio = &adapter->gpio;
+ unsigned long irq_flags = 0;
+ int bit_mask = BIT(bit);
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (bit >= 0) && (bit < LAN743X_NUMBER_OF_GPIO));
+ spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
+ if (gpio->used_bits & bit_mask) {
+ gpio->used_bits &= ~bit_mask;
+ if (gpio->output_bits & bit_mask) {
+ gpio->output_bits &= ~bit_mask;
+
+ if ((gpio->ptp_bits) & bit_mask) {
+ gpio->ptp_bits &= ~bit_mask;
+ /* disable ptp output */
+ gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_(bit);
+ lan743x_csr_write(adapter, GPIO_CFG3,
+ gpio->gpio_cfg3);
+ }
+ /* release gpio output */
+
+ /* disable gpio */
+ gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_(bit);
+ gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_(bit);
+ lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+
+ /* reset back to input */
+ gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_(bit);
+ gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_(bit);
+ lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Not Implemented, release gpio input");
+ }
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "GPIO %d is not used", bit);
+ }
+ spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+/* PTP */
+#define LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB (31249999)
+
+#define LAN743X_PTPCI_TO_PTP \
+ (container_of(ptpci, struct lan743x_ptp, ptp_clock_info))
+#define LAN743X_PTP_TO_ADAPTER \
+ (container_of(ptp, struct lan743x_adapter, ptp))
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter);
+static void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter,
+ int event_channel);
+#endif
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_adjfreq(struct ptp_clock_info *ptpci, s32 delta_ppb)
+{
+ u32 u32_delta = 0;
+ u64 u64_delta = 0;
+ u32 lan743x_rate_adj = 0;
+ bool positive = true;
+ struct lan743x_ptp *ptp = LAN743X_PTPCI_TO_PTP;
+ struct lan743x_adapter *adapter = LAN743X_PTP_TO_ADAPTER;
+
+ if ((delta_ppb < (-LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB)) ||
+ (delta_ppb > LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "delta_ppb = %d, out of range", delta_ppb);
+ return -EINVAL;
+ }
+ if (delta_ppb > 0) {
+ u32_delta = (u32)delta_ppb;
+ positive = true;
+ } else {
+ u32_delta = (u32)(-delta_ppb);
+ positive = false;
+ }
+ u64_delta = (((u64)u32_delta) * 0x800000000ULL);
+ lan743x_rate_adj = (u32)(u64_delta / 1000000000);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !(lan743x_rate_adj &
+ (~PTP_CLOCK_RATE_ADJ_VALUE_MASK_)));
+
+ if (positive)
+ lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
+
+ lan743x_csr_write(LAN743X_PTP_TO_ADAPTER, PTP_CLOCK_RATE_ADJ,
+ lan743x_rate_adj);
+
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "adjfreq, delta_ppb = %d, lan743x_rate_adj = 0x%08X",
+ delta_ppb, lan743x_rate_adj);
+ return 0;
+}
+#endif /*CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_adjtime(struct ptp_clock_info *ptpci, s64 delta)
+{
+ struct lan743x_ptp *ptp = LAN743X_PTPCI_TO_PTP;
+ struct lan743x_adapter *adapter = LAN743X_PTP_TO_ADAPTER;
+
+ lan743x_ptp_clock_step(LAN743X_PTP_TO_ADAPTER, delta);
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "adjtime, delta = %lld", delta);
+ return 0;
+}
+#endif /*CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_gettime64(struct ptp_clock_info *ptpci,
+ struct timespec64 *ts)
+{
+ struct lan743x_ptp *ptp = LAN743X_PTPCI_TO_PTP;
+ struct lan743x_adapter *adapter = LAN743X_PTP_TO_ADAPTER;
+
+ if (ts) {
+ u32 seconds = 0;
+ u32 nano_seconds = 0;
+
+ lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
+ ts->tv_sec = seconds;
+ ts->tv_nsec = nano_seconds;
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "gettime = %u.%09u", seconds, nano_seconds);
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev, "ts == NULL");
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif /*CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci,
+ const struct timespec64 *ts)
+{
+ struct lan743x_ptp *ptp = LAN743X_PTPCI_TO_PTP;
+ struct lan743x_adapter *adapter = LAN743X_PTP_TO_ADAPTER;
+
+ if (ts) {
+ u32 seconds = 0;
+ u32 nano_seconds = 0;
+
+ if ((ts->tv_sec > 0xFFFFFFFFLL) ||
+ (ts->tv_sec < 0)) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "ts->tv_sec out of range, %ld",
+ ts->tv_sec);
+ return -EINVAL;
+ }
+ if ((ts->tv_nsec >= 1000000000L) ||
+ (ts->tv_nsec < 0)) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "ts->tv_nsec out of range, %ld",
+ ts->tv_nsec);
+ return -EINVAL;
+ }
+ seconds = ts->tv_sec;
+ nano_seconds = ts->tv_nsec;
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "settime = %u.%09u", seconds, nano_seconds);
+ lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev, "ts == NULL");
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif /*CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_enable_pps(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+ int result = -ENODEV;
+ u32 current_seconds = 0;
+ u32 target_seconds = 0;
+ u32 general_config = 0;
+
+ if (ptp->pps_event_ch >= 0) {
+ NETIF_INFO(adapter, drv, adapter->netdev, "PPS already ON");
+ result = 0;
+ goto done;
+ }
+
+ ptp->pps_event_ch = lan743x_ptp_reserve_event_ch(adapter);
+ if (ptp->pps_event_ch < 0) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Failed to reserve event channel for PPS");
+ goto done;
+ }
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, ptp->pps_gpio_bit < 0);
+
+ ptp->pps_gpio_bit = lan743x_gpio_reserve_ptp_output(adapter, 0,
+ ptp->pps_event_ch);
+
+ if (ptp->pps_gpio_bit < 0) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Failed to reserve gpio 0 for PPS");
+ goto done;
+ }
+
+ lan743x_ptp_clock_get(adapter, ¤t_seconds, NULL, NULL);
+
+ /* set the first target ahead by 2 seconds
+ * to make sure its not missed
+ */
+ target_seconds = current_seconds + 2;
+
+ /* set the new target */
+ lan743x_csr_write(adapter,
+ PTP_CLOCK_TARGET_SEC_X(ptp->pps_event_ch),
+ 0xFFFF0000);
+ lan743x_csr_write(adapter,
+ PTP_CLOCK_TARGET_NS_X(ptp->pps_event_ch), 0);
+
+ general_config = lan743x_csr_read(adapter,
+ PTP_GENERAL_CONFIG);
+
+ general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(
+ ptp->pps_event_ch));
+ general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_(
+ ptp->pps_event_ch,
+ PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_);
+ general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_(
+ ptp->pps_event_ch);
+ lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
+
+ /* set the reload to one second steps */
+ lan743x_csr_write(adapter,
+ PTP_CLOCK_TARGET_RELOAD_SEC_X(ptp->pps_event_ch),
+ 1);
+ lan743x_csr_write(adapter,
+ PTP_CLOCK_TARGET_RELOAD_NS_X(ptp->pps_event_ch),
+ 0);
+
+ /* set the new target */
+ lan743x_csr_write(adapter,
+ PTP_CLOCK_TARGET_SEC_X(ptp->pps_event_ch),
+ target_seconds);
+ lan743x_csr_write(adapter,
+ PTP_CLOCK_TARGET_NS_X(ptp->pps_event_ch),
+ 0);
+
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "PPS enabled, channel = %d, gpio = %d",
+ ptp->pps_event_ch, ptp->pps_gpio_bit);
+
+ result = 0;
+done:
+ if (result < 0) {
+ if (ptp->pps_gpio_bit >= 0) {
+ lan743x_gpio_release(adapter, ptp->pps_gpio_bit);
+ ptp->pps_gpio_bit = -1;
+ }
+ if (ptp->pps_event_ch >= 0) {
+ lan743x_ptp_release_event_ch(adapter,
+ ptp->pps_event_ch);
+ ptp->pps_event_ch = -1;
+ }
+ }
+ return result;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_disable_pps(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ if (ptp->pps_gpio_bit >= 0) {
+ lan743x_gpio_release(adapter, ptp->pps_gpio_bit);
+ ptp->pps_gpio_bit = -1;
+ }
+
+ if (ptp->pps_event_ch >= 0) {
+ u32 general_config = 0;
+
+ /* set target to far in the future, effectively disabling it */
+ lan743x_csr_write(adapter,
+ PTP_CLOCK_TARGET_SEC_X(ptp->pps_event_ch),
+ 0xFFFF0000);
+ lan743x_csr_write(adapter,
+ PTP_CLOCK_TARGET_NS_X(ptp->pps_event_ch), 0);
+
+ general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
+ general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_(
+ ptp->pps_event_ch);
+ lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
+ lan743x_ptp_release_event_ch(adapter, ptp->pps_event_ch);
+ ptp->pps_event_ch = -1;
+ }
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci,
+ struct ptp_clock_request *request, int on)
+{
+ struct lan743x_ptp *ptp = LAN743X_PTPCI_TO_PTP;
+ struct lan743x_adapter *adapter = NULL;
+
+ adapter = LAN743X_PTP_TO_ADAPTER;
+ if (request) {
+ switch (request->type) {
+ case PTP_CLK_REQ_EXTTS:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "request->type == PTP_CLK_REQ_EXTTS");
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "request->extts.index = %d",
+ request->extts.index);
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "request->extts.flags = 0x%08X",
+ request->extts.flags);
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "on = %d", on);
+ return -EINVAL;
+ case PTP_CLK_REQ_PEROUT:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "request->type == PTP_CLK_REQ_PEROUT");
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "on = %d", on);
+ {
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " start = %lld.%09u",
+ request->perout.start.sec,
+ request->perout.start.nsec);
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " period = %lld.%09u",
+ request->perout.period.sec,
+ request->perout.period.nsec);
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " index = %u",
+ request->perout.index);
+ }
+ return -EINVAL;
+ case PTP_CLK_REQ_PPS:
+ if (on) {
+ if (lan743x_ptp_enable_pps(adapter) >= 0) {
+ NETIF_INFO(adapter, drv,
+ adapter->netdev,
+ "PPS is ON");
+ } else {
+ NETIF_WARNING(adapter, drv,
+ adapter->netdev,
+ "Error starting PPS");
+ }
+ } else {
+ lan743x_ptp_disable_pps(adapter);
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "PPS is OFF");
+ }
+ break;
+ default:
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "request->type == %d, Unknown",
+ request->type);
+ break;
+ }
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev, "request == NULL");
+ }
+ return 0;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+static void lan743x_ptp_isr(void *context)
+{
+ int enable_flag = 1;
+ u32 ptp_int_sts = 0;
+ struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+ struct lan743x_ptp *ptp = NULL;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+ ptp = &adapter->ptp;
+
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
+
+ ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS);
+ if (ptp_int_sts & PTP_INT_BIT_TX_TS_) {
+ tasklet_schedule(&ptp->ptp_isr_bottom_half);
+ enable_flag = 0;/* tasklet will re-enable later */
+ }
+ if (ptp_int_sts & PTP_INT_BIT_TX_SWTS_ERR_) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "PTP TX Software Timestamp Error");
+ /* clear int status bit */
+ lan743x_csr_write(adapter, PTP_INT_STS,
+ PTP_INT_BIT_TX_SWTS_ERR_);
+ }
+ if (ptp_int_sts & PTP_INT_BIT_TIMER_B_) {
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "PTP TIMER B Interrupt");
+ /* clear int status bit */
+ lan743x_csr_write(adapter, PTP_INT_STS,
+ PTP_INT_BIT_TIMER_B_);
+ }
+ if (ptp_int_sts & PTP_INT_BIT_TIMER_A_) {
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "PTP TIMER A Interrupt");
+ /* clear int status bit */
+ lan743x_csr_write(adapter, PTP_INT_STS,
+ PTP_INT_BIT_TIMER_A_);
+ }
+
+ if (enable_flag) {
+ /* re-enable isr */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+ }
+}
+
+static void lan743x_ptp_tx_ts_complete(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+ int i;
+ int c;
+
+ mutex_lock(&ptp->tx_ts_lock);
+ c = ptp->tx_ts_skb_queue_size;
+
+ if (c > ptp->tx_ts_queue_size)
+ c = ptp->tx_ts_queue_size;
+ if (c <= 0)
+ goto done;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ c <=
+ LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS);
+ for (i = 0; i < c; i++) {
+ struct skb_shared_hwtstamps tstamps;
+ struct sk_buff *skb = ptp->tx_ts_skb_queue[i];
+ u32 seconds = ptp->tx_ts_seconds_queue[i];
+ u32 nseconds = ptp->tx_ts_nseconds_queue[i];
+
+ NETIF_ASSERT(adapter, drv,
+ adapter->netdev, skb);
+
+ memset(&tstamps, 0, sizeof(tstamps));
+ tstamps.hwtstamp = ktime_set(seconds, nseconds);
+ skb_tstamp_tx(skb, &tstamps);
+ dev_kfree_skb(skb);
+
+ ptp->tx_ts_skb_queue[i] = NULL;
+ ptp->tx_ts_seconds_queue[i] = 0;
+ ptp->tx_ts_nseconds_queue[i] = 0;
+ }
+
+ /* shift queue */
+ for (i = c;
+ i < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS;
+ i++) {
+ ptp->tx_ts_skb_queue[i - c] = ptp->tx_ts_skb_queue[i];
+ ptp->tx_ts_seconds_queue[i - c] = ptp->tx_ts_seconds_queue[i];
+ ptp->tx_ts_nseconds_queue[i - c] = ptp->tx_ts_nseconds_queue[i];
+
+ ptp->tx_ts_skb_queue[i] = NULL;
+ ptp->tx_ts_seconds_queue[i] = 0;
+ ptp->tx_ts_nseconds_queue[i] = 0;
+ }
+ ptp->tx_ts_skb_queue_size -= c;
+ ptp->tx_ts_queue_size -= c;
+done:
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ ptp->pending_tx_timestamps >= c);
+ ptp->pending_tx_timestamps -= c;
+ mutex_unlock(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_tx_ts_enqueue_skb(struct lan743x_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, skb);
+
+ mutex_lock(&ptp->tx_ts_lock);
+ if (ptp->tx_ts_skb_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size]);
+ ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size] = skb;
+ ptp->tx_ts_skb_queue_size++;
+ } else {
+ /* this should never happen, so long as the tx channel
+ * calls and honors the result from
+ * lan743x_ptp_request_tx_timestamp
+ */
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "tx ts skb queue overflow");
+ dev_kfree_skb(skb);
+ }
+ mutex_unlock(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_tx_ts_enqueue_ts(struct lan743x_adapter *adapter,
+ u32 seconds, u32 nano_seconds)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ mutex_lock(&ptp->tx_ts_lock);
+ if (ptp->tx_ts_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !ptp->tx_ts_seconds_queue[
+ ptp->tx_ts_queue_size]);
+ ptp->tx_ts_seconds_queue[ptp->tx_ts_queue_size] = seconds;
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !ptp->tx_ts_nseconds_queue[
+ ptp->tx_ts_queue_size]);
+ ptp->tx_ts_nseconds_queue[ptp->tx_ts_queue_size] = nano_seconds;
+ ptp->tx_ts_queue_size++;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "tx ts queue overflow");
+ }
+ mutex_unlock(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_isr_bottom_half(unsigned long param)
+{
+ struct lan743x_adapter *adapter = (struct lan743x_adapter *)param;
+ bool new_timestamp_available = false;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+
+ while (lan743x_csr_read(adapter, PTP_INT_STS) & PTP_INT_BIT_TX_TS_) {
+ u32 cap_info = lan743x_csr_read(adapter, PTP_CAP_INFO);
+
+ if (PTP_CAP_INFO_TX_TS_CNT_GET_(cap_info) > 0) {
+ u32 seconds = lan743x_csr_read(adapter,
+ PTP_TX_EGRESS_SEC);
+ u32 nsec = lan743x_csr_read(adapter, PTP_TX_EGRESS_NS);
+ u32 cause = (nsec &
+ PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_);
+
+ if (cause == PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_) {
+ nsec &= PTP_TX_EGRESS_NS_TS_NS_MASK_;
+ lan743x_ptp_tx_ts_enqueue_ts(
+ adapter, seconds, nsec);
+ new_timestamp_available = true;
+ } else if (cause ==
+ PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Auto capture cause not supported");
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "unknown tx timestamp capture cause");
+ }
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "TX TS INT but no TX TS CNT");
+ }
+ lan743x_csr_write(adapter, PTP_INT_STS, PTP_INT_BIT_TX_TS_);
+ }
+
+ if (new_timestamp_available)
+ lan743x_ptp_tx_ts_complete(adapter);
+
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+}
+
+static void lan743x_ptp_sync_to_system_clock(struct lan743x_adapter *adapter)
+{
+ struct timeval tv;
+
+ memset(&tv, 0, sizeof(tv));
+ do_gettimeofday(&tv);
+ lan743x_ptp_clock_set(adapter, tv.tv_sec, tv.tv_usec * 1000, 0);
+}
+
+static int lan743x_ptp_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, ptp);
+ memset(ptp, 0, sizeof(*ptp));
+
+ mutex_init(&ptp->command_lock);
+ mutex_init(&ptp->tx_ts_lock);
+
+ tasklet_init(&ptp->ptp_isr_bottom_half,
+ lan743x_ptp_isr_bottom_half, (unsigned long)adapter);
+ tasklet_disable(&ptp->ptp_isr_bottom_half);
+
+ ptp->used_event_ch = 0;
+ ptp->pps_event_ch = -1;
+ ptp->pps_gpio_bit = -1;
+
+ return 0;
+}
+
+static void lan743x_ptp_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ memset(ptp, 0, sizeof(*ptp));
+}
+
+static int lan743x_ptp_open(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+ int ret = -ENODEV;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !ptp->pending_tx_timestamps);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !ptp->tx_ts_skb_queue_size);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !ptp->tx_ts_queue_size);
+
+ lan743x_ptp_reset(adapter);
+ lan743x_ptp_sync_to_system_clock(adapter);
+ lan743x_ptp_enable(adapter);
+
+ tasklet_enable(&ptp->ptp_isr_bottom_half);
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+ lan743x_csr_write(adapter, PTP_INT_EN_SET,
+ PTP_INT_BIT_TX_SWTS_ERR_ | PTP_INT_BIT_TX_TS_);
+ ptp->flags |= PTP_FLAG_ISR_ENABLED;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+ snprintf(ptp->pin_config[0].name, 32, "lan743x_ptp_pin_0");
+ ptp->pin_config[0].index = 0;
+ ptp->pin_config[0].func = PTP_PF_PEROUT;
+ ptp->pin_config[0].chan = 0;
+
+ ptp->ptp_clock_info.owner = THIS_MODULE;
+ snprintf(ptp->ptp_clock_info.name, 16, "%pm",
+ adapter->netdev->dev_addr);
+ ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB;
+ ptp->ptp_clock_info.n_alarm = 0;
+ ptp->ptp_clock_info.n_ext_ts = 0;
+ ptp->ptp_clock_info.n_per_out = 0;
+ ptp->ptp_clock_info.n_pins = 0;
+ ptp->ptp_clock_info.pps = 1;
+ ptp->ptp_clock_info.pin_config = NULL;
+ ptp->ptp_clock_info.adjfreq = lan743x_ptpci_adjfreq;
+ ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime;
+ ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64;
+ ptp->ptp_clock_info.getcrosststamp = NULL;
+ ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64;
+ ptp->ptp_clock_info.enable = lan743x_ptpci_enable;
+ ptp->ptp_clock_info.verify = NULL;
+
+ ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info,
+ &adapter->pci.pdev->dev);
+
+ if (IS_ERR(ptp->ptp_clock)) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "ptp_clock_register failed");
+ goto done;
+ }
+ ptp->flags |= PTP_FLAG_PTP_CLOCK_REGISTERED;
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "successfully registered ptp clock");
+#endif
+
+ ret = 0;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+done:
+ if (ret)
+ lan743x_ptp_close(adapter);
+#endif
+
+ return ret;
+}
+
+static void lan743x_ptp_close(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+ int index;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+ if (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev, ptp->ptp_clock);
+ ptp_clock_unregister(ptp->ptp_clock);
+ ptp->ptp_clock = NULL;
+ ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED;
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "ptp clock unregister");
+ }
+#endif
+
+ if (ptp->flags & PTP_FLAG_ISR_ENABLED) {
+ lan743x_csr_write(adapter, PTP_INT_EN_CLR,
+ PTP_INT_BIT_TX_SWTS_ERR_ |
+ PTP_INT_BIT_TX_TS_);
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
+ tasklet_disable(&ptp->ptp_isr_bottom_half);
+ ptp->flags &= ~PTP_FLAG_ISR_ENABLED;
+ }
+
+ /* clean up pending timestamp requests */
+ lan743x_ptp_tx_ts_complete(adapter);
+ mutex_lock(&ptp->tx_ts_lock);
+ for (index = 0;
+ index < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS;
+ index++) {
+ struct sk_buff *skb = ptp->tx_ts_skb_queue[index];
+
+ if (skb)
+ dev_kfree_skb(skb);
+ ptp->tx_ts_skb_queue[index] = NULL;
+ ptp->tx_ts_seconds_queue[index] = 0;
+ ptp->tx_ts_nseconds_queue[index] = 0;
+ }
+ ptp->tx_ts_skb_queue_size = 0;
+ ptp->tx_ts_queue_size = 0;
+ ptp->pending_tx_timestamps = 0;
+ mutex_unlock(&ptp->tx_ts_lock);
+
+ lan743x_ptp_disable(adapter);
+}
+
+static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter)
+{
+ if (lan743x_csr_read(adapter, PTP_CMD_CTL) & PTP_CMD_CTL_PTP_ENABLE_)
+ return true;
+ return false;
+}
+
+static void lan743x_ptp_wait_till_cmd_done(struct lan743x_adapter *adapter,
+ u32 bit_mask)
+{
+ int timeout = 1000;
+ u32 data = 0;
+
+ while (timeout && (data = (lan743x_csr_read(
+ adapter, PTP_CMD_CTL) &
+ bit_mask))) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "timeout waiting for cmd to be done, cmd = 0x%08X",
+ bit_mask);
+ }
+}
+
+static void lan743x_ptp_enable(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ mutex_lock(&ptp->command_lock);
+
+ if (lan743x_ptp_is_enabled(adapter)) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "PTP already enabled");
+ goto done;
+ }
+ lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_ENABLE_);
+done:
+ mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_disable(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ mutex_lock(&ptp->command_lock);
+ if (!lan743x_ptp_is_enabled(adapter)) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "PTP already disabled");
+ goto done;
+ }
+
+ lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_DISABLE_);
+ lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_ENABLE_);
+done:
+ mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_reset(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ mutex_lock(&ptp->command_lock);
+
+ if (lan743x_ptp_is_enabled(adapter)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Attempting reset while enabled");
+ goto done;
+ }
+
+ lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_RESET_);
+ lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_RESET_);
+done:
+ mutex_unlock(&ptp->command_lock);
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+ int index = 0;
+ int result = -ENODEV;
+
+ mutex_lock(&ptp->command_lock);
+ for (index = 0; index < LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS; index++) {
+ if (!(test_bit(index, &ptp->used_event_ch))) {
+ ptp->used_event_ch |= BIT(index);
+ result = index;
+ break;
+ }
+ }
+ mutex_unlock(&ptp->command_lock);
+ return result;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter,
+ int event_channel)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (event_channel >= 0) &&
+ (event_channel < LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS));
+ mutex_lock(&ptp->command_lock);
+ if (test_bit(event_channel, &ptp->used_event_ch)) {
+ ptp->used_event_ch &= ~BIT(event_channel);
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "attempted release on a not used event_channel = %d",
+ event_channel);
+ }
+ mutex_unlock(&ptp->command_lock);
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
+ u32 *seconds, u32 *nano_seconds,
+ u32 *sub_nano_seconds)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ mutex_lock(&ptp->command_lock);
+
+ lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_);
+ lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_);
+
+ if (seconds)
+ (*seconds) = lan743x_csr_read(adapter, PTP_CLOCK_SEC);
+
+ if (nano_seconds)
+ (*nano_seconds) = lan743x_csr_read(adapter, PTP_CLOCK_NS);
+
+ if (sub_nano_seconds)
+ (*sub_nano_seconds) =
+ lan743x_csr_read(adapter, PTP_CLOCK_SUBNS);
+
+ mutex_unlock(&ptp->command_lock);
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
+ u32 seconds, u32 nano_seconds,
+ u32 sub_nano_seconds)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ mutex_lock(&ptp->command_lock);
+
+ lan743x_csr_write(adapter, PTP_CLOCK_SEC, seconds);
+ lan743x_csr_write(adapter, PTP_CLOCK_NS, nano_seconds);
+ lan743x_csr_write(adapter, PTP_CLOCK_SUBNS, sub_nano_seconds);
+
+ lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
+ lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
+ mutex_unlock(&ptp->command_lock);
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
+ s64 time_step_ns)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+ u64 abs_time_step_ns = 0;
+ s32 seconds = 0;
+ u32 nano_seconds = 0;
+
+ if (time_step_ns > 15000000000LL) {
+ /* convert to clock set */
+ u32 seconds = 0;
+ u32 nano_seconds = 0;
+
+ lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
+ seconds += (time_step_ns / 1000000000LL);
+ nano_seconds += (time_step_ns % 1000000000LL);
+ if (nano_seconds >= 1000000000) {
+ seconds++;
+ nano_seconds -= 1000000000;
+ }
+ lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
+ return;
+ } else if (time_step_ns < -15000000000LL) {
+ /* convert to clock set */
+ u32 seconds = 0;
+ u32 nano_seconds = 0;
+ u32 nano_seconds_step = 0;
+
+ lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
+ seconds -= (time_step_ns / 1000000000LL);
+ nano_seconds_step = (time_step_ns % 1000000000LL);
+ if (nano_seconds < nano_seconds_step) {
+ seconds--;
+ nano_seconds += 1000000000;
+ }
+ nano_seconds -= nano_seconds_step;
+ lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
+ return;
+ }
+
+ /* do clock step */
+
+ if (time_step_ns >= 0) {
+ abs_time_step_ns = (u64)(time_step_ns);
+ seconds = (s32)(abs_time_step_ns / 1000000000);
+ nano_seconds = (u32)(abs_time_step_ns % 1000000000);
+ } else {
+ abs_time_step_ns = (u64)(-time_step_ns);
+ seconds = -((s32)(abs_time_step_ns / 1000000000));
+ nano_seconds = (u32)(abs_time_step_ns % 1000000000);
+ if (nano_seconds > 0) {
+ /* subtracting nano seconds is not allowed
+ * convert to subtracting from seconds,
+ * and adding to nanoseconds
+ */
+ seconds--;
+ nano_seconds = (1000000000 - nano_seconds);
+ }
+ }
+
+ if (nano_seconds > 0) {
+ /* add 8 ns to cover the likely normal increment */
+ nano_seconds += 8;
+ }
+
+ if (nano_seconds >= 1000000000) {
+ /* carry into seconds */
+ seconds++;
+ nano_seconds -= 1000000000;
+ }
+
+ while (seconds) {
+ mutex_lock(&ptp->command_lock);
+ if (seconds > 0) {
+ u32 adjustment_value = (u32)seconds;
+
+ if (adjustment_value > 0xF)
+ adjustment_value = 0xF;
+ lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+ PTP_CLOCK_STEP_ADJ_DIR_ |
+ adjustment_value);
+ seconds -= ((s32)adjustment_value);
+ } else {
+ u32 adjustment_value = (u32)(-seconds);
+
+ if (adjustment_value > 0xF)
+ adjustment_value = 0xF;
+ lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+ adjustment_value);
+ seconds += ((s32)adjustment_value);
+ }
+ lan743x_csr_write(adapter, PTP_CMD_CTL,
+ PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
+ lan743x_ptp_wait_till_cmd_done(adapter,
+ PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
+ mutex_unlock(&ptp->command_lock);
+ }
+ if (nano_seconds) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ nano_seconds < 1000000000);
+ mutex_lock(&ptp->command_lock);
+ lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+ PTP_CLOCK_STEP_ADJ_DIR_ |
+ (nano_seconds &
+ PTP_CLOCK_STEP_ADJ_VALUE_MASK_));
+ lan743x_csr_write(adapter, PTP_CMD_CTL,
+ PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
+ lan743x_ptp_wait_till_cmd_done(adapter,
+ PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
+ mutex_unlock(&ptp->command_lock);
+ }
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+static bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+ bool result = false;
+
+ mutex_lock(&ptp->tx_ts_lock);
+ if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+ ptp->pending_tx_timestamps++;
+ result = true;/* request granted */
+ }
+ mutex_unlock(&ptp->tx_ts_lock);
+ return result;
+}
+
+static void lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ mutex_lock(&ptp->tx_ts_lock);
+ if (ptp->pending_tx_timestamps > 0) {
+ ptp->pending_tx_timestamps--;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "unrequest failed, pending_tx_timestamps==0");
+ }
+ mutex_unlock(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter,
+ struct sk_buff *skb)
+{
+ NETIF_ASSERT(adapter, drv, adapter->netdev, skb);
+ lan743x_ptp_tx_ts_enqueue_skb(adapter, skb);
+
+ lan743x_ptp_tx_ts_complete(adapter);
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_get_clock_index(struct lan743x_adapter *adapter)
+{
+ struct lan743x_ptp *ptp = &adapter->ptp;
+
+ if (ptp->ptp_clock)
+ return ptp_clock_index(ptp->ptp_clock);
+ return -1;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+/* MAC */
+#define MAC_FLAG_MDIOBUS_ALLOCATED BIT(0)
+#define MAC_FLAG_MDIOBUS_REGISTERED BIT(1)
+
+static void lan743x_mac_isr(void *context)
+{
+ struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+ struct lan743x_mac *mac = NULL;
+ u32 mac_int_sts = 0;
+ u32 mac_int_en = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+ mac = &adapter->mac;
+
+ /* disable isr */
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAC_);
+
+ mac_int_sts = lan743x_csr_read(adapter, MAC_INT_STS);
+ mac_int_en = lan743x_csr_read(adapter, MAC_INT_EN_SET);
+ mac_int_sts = mac_int_sts & mac_int_en;
+ if (mac_int_sts & MAC_INT_BIT_MAC_ERR_) {
+ u32 err_sts = lan743x_csr_read(adapter, MAC_ERR_STS);
+
+ if (err_sts & MAC_ERR_STS_RESERVED_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Reserved ERROR, err_sts = 0x%08X",
+ err_sts);
+ if (err_sts & MAC_ERR_STS_LEN_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Length Field Error");
+ if (err_sts & MAC_ERR_STS_RXERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev, "RX Error");
+ if (err_sts & MAC_ERR_STS_LFERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Large Frame Error");
+ if (err_sts & MAC_ERR_STS_RWTERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Receive Watchdog Timer Expired");
+ if (err_sts & MAC_ERR_STS_ECERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Excessive Collision Error");
+ if (err_sts & MAC_ERR_STS_URERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Under Run Error");
+
+ /* clear error bits */
+ lan743x_csr_write(adapter, MAC_ERR_STS, err_sts);
+ }
+ if (mac_int_sts & (~MAC_INT_BIT_MAC_ERR_))
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Unhandled MAC Interrupt");
+
+ /* clear mac int status bits */
+ lan743x_csr_write(adapter, MAC_INT_STS, mac_int_sts);
+
+ /* enable isr */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAC_);
+}
+
+static int lan743x_mdiobus_read(struct mii_bus *bus, int phy_id, int index);
+static int lan743x_mdiobus_write(struct mii_bus *bus, int phy_id, int index,
+ u16 regval);
+
+static int lan743x_mac_reset(struct lan743x_adapter *adapter)
+{
+ u32 data = 0;
+ int timeout = 100;
+
+ lan743x_csr_write(adapter, MAC_CR, MAC_CR_RST_);
+ while (timeout &&
+ ((data = lan743x_csr_read(adapter, MAC_CR)) & MAC_CR_RST_)) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data & MAC_CR_RST_) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "timed out waiting for mac reset to finish");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int lan743x_mac_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+ struct net_device *netdev;
+ u32 data;
+ int ret = -ENODEV;
+ u32 mac_addr_hi = 0;
+ u32 mac_addr_lo = 0;
+ bool mac_address_valid = true;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, mac);
+
+ memset(mac, 0, sizeof(*mac));
+
+ netdev = adapter->netdev;
+
+ ret = lan743x_mac_reset(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "mac reset failed");
+ goto clean_up;
+ }
+
+ /* setup auto duplex, and speed detection */
+ data = lan743x_csr_read(adapter, MAC_CR);
+ data |= MAC_CR_ADD_ | MAC_CR_ASD_;
+ data |= MAC_CR_CNTR_RST_;
+ lan743x_csr_write(adapter, MAC_CR, data);
+
+ mutex_init(&mac->tx_mutex);
+ mac->tx_enable_bits = 0;
+ mutex_init(&mac->rx_mutex);
+ mac->rx_enable_bits = 0;
+
+ mac->mdiobus = mdiobus_alloc();
+ if (!(mac->mdiobus)) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "mdiobus_alloc failed");
+ ret = -ENOMEM;
+ goto clean_up;
+ }
+ mac->flags |= MAC_FLAG_MDIOBUS_ALLOCATED;
+
+ mutex_init(&mac->mii_mutex);
+ mac->mdiobus->priv = (void *)adapter;
+ mac->mdiobus->read = lan743x_mdiobus_read;
+ mac->mdiobus->write = lan743x_mdiobus_write;
+ mac->mdiobus->name = "lan743x-mdiobus";
+
+ snprintf(mac->mdiobus->id, MII_BUS_ID_SIZE,
+ "pci-%s", pci_name(adapter->pci.pdev));
+
+ /* set to internal PHY id */
+ mac->mdiobus->phy_mask = ~(1 << 1);
+
+ /* register mdiobus */
+ ret = mdiobus_register(mac->mdiobus);
+ if (ret < 0) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "failed to register MDIO bus");
+ goto clean_up;
+ }
+ NETIF_INFO(adapter, probe, adapter->netdev,
+ "successfully registered MDIO bus, %s", mac->mdiobus->id);
+ mac->flags |= MAC_FLAG_MDIOBUS_REGISTERED;
+
+ mac_addr_hi = lan743x_csr_read(adapter, MAC_RX_ADDRH);
+ mac_addr_lo = lan743x_csr_read(adapter, MAC_RX_ADDRL);
+ mac->mac_address[0] = mac_addr_lo & 0xFF;
+ mac->mac_address[1] = (mac_addr_lo >> 8) & 0xFF;
+ mac->mac_address[2] = (mac_addr_lo >> 16) & 0xFF;
+ mac->mac_address[3] = (mac_addr_lo >> 24) & 0xFF;
+ mac->mac_address[4] = mac_addr_hi & 0xFF;
+ mac->mac_address[5] = (mac_addr_hi >> 8) & 0xFF;
+
+ if (((mac_addr_hi & 0x0000FFFF) == 0x0000FFFF) &&
+ (mac_addr_lo == 0xFFFFFFFF)) {
+ NETIF_INFO(adapter, probe, adapter->netdev,
+ "MAC address not available from EEPROM or OTP");
+ mac_address_valid = false;
+ } else if (!is_valid_ether_addr(mac->mac_address)) {
+ NETIF_WARNING(adapter, probe, adapter->netdev,
+ "MAC address is not valid");
+ mac_address_valid = false;
+ }
+
+ if (!mac_address_valid) {
+ random_ether_addr(mac->mac_address);
+ NETIF_INFO(adapter, probe, adapter->netdev,
+ "MAC address set to random address");
+ mac_addr_lo = mac->mac_address[0] |
+ (mac->mac_address[1] << 8) |
+ (mac->mac_address[2] << 16) |
+ (mac->mac_address[3] << 24);
+ mac_addr_hi = mac->mac_address[4] |
+ (mac->mac_address[5] << 8);
+ }
+
+ lan743x_csr_write(adapter, MAC_RX_ADDRL, mac_addr_lo);
+ lan743x_csr_write(adapter, MAC_RX_ADDRH, mac_addr_hi);
+ NETIF_INFO(adapter, probe, adapter->netdev,
+ "MAC Address = %02X:%02X:%02X:%02X:%02X:%02X",
+ mac->mac_address[0], mac->mac_address[1],
+ mac->mac_address[2], mac->mac_address[3],
+ mac->mac_address[4], mac->mac_address[5]);
+
+ ether_addr_copy(netdev->dev_addr, mac->mac_address);
+
+ ret = 0;
+
+clean_up:
+ if (ret)
+ lan743x_mac_cleanup(adapter);
+ return ret;
+}
+
+static void lan743x_mac_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+
+ if (mac->tx_enable_bits) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Some TX channels have not been disabled");
+ }
+ if (mac->rx_enable_bits) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Some RX Channels have not been disabled");
+ }
+
+ if (mac->flags & MAC_FLAG_MDIOBUS_REGISTERED) {
+ mdiobus_unregister(mac->mdiobus);
+ mac->flags &= ~MAC_FLAG_MDIOBUS_REGISTERED;
+ }
+
+ if (mac->flags & MAC_FLAG_MDIOBUS_ALLOCATED) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev, mac->mdiobus);
+ mdiobus_free(mac->mdiobus);
+ mac->mdiobus = NULL;
+ mac->flags &= ~MAC_FLAG_MDIOBUS_ALLOCATED;
+ }
+
+ memset(mac, 0, sizeof(*mac));
+}
+
+static int lan743x_mac_open(struct lan743x_adapter *adapter)
+{
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAC_);
+ lan743x_csr_write(adapter, MAC_INT_EN_SET, MAC_INT_BIT_MAC_ERR_);
+
+ return 0;
+}
+
+static void lan743x_mac_close(struct lan743x_adapter *adapter)
+{
+ lan743x_csr_write(adapter, MAC_INT_EN_CLR, MAC_INT_BIT_MAC_ERR_);
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAC_);
+}
+
+static void lan743x_mac_get_address(struct lan743x_adapter *adapter,
+ u8 *mac_addr)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, mac_addr);
+ ether_addr_copy(mac_addr, mac->mac_address);
+}
+
+#define MAC_MII_READ 1
+#define MAC_MII_WRITE 0
+static inline u32 lan743x_mac_mii_access(int id, int index, int read)
+{
+ u32 ret;
+
+ ret = ((u32)id << MAC_MII_ACC_PHY_ADDR_SHIFT_) &
+ MAC_MII_ACC_PHY_ADDR_MASK_;
+ ret |= ((u32)index << MAC_MII_ACC_MIIRINDA_SHIFT_) &
+ MAC_MII_ACC_MIIRINDA_MASK_;
+ if (read)
+ ret |= MAC_MII_ACC_MII_READ_;
+ else
+ ret |= MAC_MII_ACC_MII_WRITE_;
+ ret |= MAC_MII_ACC_MII_BUSY_;
+
+ return ret;
+}
+
+static int lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter *adapter)
+{
+ unsigned long start_time = jiffies;
+ u32 data;
+
+ do {
+ data = lan743x_csr_read(adapter, MAC_MII_ACC);
+
+ if (!(data & MAC_MII_ACC_MII_BUSY_))
+ return 0;
+ } while (!time_after(jiffies, start_time + HZ));
+
+ NETIF_ERROR(adapter, drv, adapter->netdev, "mii is busy");
+ return -EIO;
+}
+
+static int lan743x_mac_mii_read(struct lan743x_adapter *adapter,
+ int phy_id, int index)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+ u32 val, addr;
+ int ret;
+
+ mutex_lock(&mac->mii_mutex);
+
+ /* comfirm MII not busy */
+ ret = lan743x_mac_mii_wait_till_not_busy(adapter);
+ if (ret < 0)
+ goto done;
+
+ /* set the address, index & direction (read from PHY) */
+ addr = lan743x_mac_mii_access(phy_id, index, MAC_MII_READ);
+ lan743x_csr_write(adapter, MAC_MII_ACC, addr);
+
+ ret = lan743x_mac_mii_wait_till_not_busy(adapter);
+ if (ret < 0)
+ goto done;
+
+ val = lan743x_csr_read(adapter, MAC_MII_DATA);
+
+ ret = (int)(val & 0xFFFF);
+
+done:
+ mutex_unlock(&mac->mii_mutex);
+#if (LAN743X_PHY_TRACE_ENABLE != 0)
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "MII READ: phy_id = %d, index = %d, value = 0x%04X",
+ phy_id, index, ret);
+#endif
+ return ret;
+}
+
+static int lan743x_mdiobus_read(struct mii_bus *bus, int phy_id, int index)
+{
+ struct lan743x_adapter *adapter = bus->priv;
+
+ return lan743x_mac_mii_read(adapter, phy_id, index);
+}
+
+static int lan743x_mac_mii_write(struct lan743x_adapter *adapter,
+ int phy_id, int index, u16 regval)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+ u32 val, addr;
+ int ret;
+
+#if (LAN743X_PHY_TRACE_ENABLE != 0)
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "MII WRITE: phy_id = %d, index = %d, value = 0x%04X",
+ phy_id, index, regval);
+#endif
+
+ mutex_lock(&mac->mii_mutex);
+
+ /* confirm MII not busy */
+ ret = lan743x_mac_mii_wait_till_not_busy(adapter);
+ if (ret < 0)
+ goto done;
+
+ val = (u32)regval;
+ lan743x_csr_write(adapter, MAC_MII_DATA, val);
+
+ /* set the address, index & direction (write to PHY) */
+ addr = lan743x_mac_mii_access(phy_id, index, MAC_MII_WRITE);
+ lan743x_csr_write(adapter, MAC_MII_ACC, addr);
+
+ ret = lan743x_mac_mii_wait_till_not_busy(adapter);
+
+done:
+ mutex_unlock(&mac->mii_mutex);
+ return ret;
+}
+
+static int lan743x_mdiobus_write(struct mii_bus *bus,
+ int phy_id, int index, u16 regval)
+{
+ struct lan743x_adapter *adapter = bus->priv;
+
+ return lan743x_mac_mii_write(adapter, phy_id, index, regval);
+}
+
+static void lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter,
+ bool tx_enable, bool rx_enable)
+{
+ u32 flow_setting = 0;
+
+ /* set maximum pause time because when fifo space frees
+ * up a zero value pause frame will be sent to release the pause
+ */
+ flow_setting = MAC_FLOW_CR_FCPT_MASK_;
+
+ if (tx_enable)
+ flow_setting |= MAC_FLOW_CR_TX_FCEN_;
+
+ if (rx_enable)
+ flow_setting |= MAC_FLOW_CR_RX_FCEN_;
+
+ lan743x_csr_write(adapter, MAC_FLOW, flow_setting);
+}
+
+static int lan743x_mac_tx_enable_all(struct lan743x_adapter *adapter)
+{
+ u32 data = 0;
+
+ data = lan743x_csr_read(adapter, MAC_TX);
+ if (data & MAC_TX_TXEN_) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempted to enable mac tx, when already enabled");
+ goto done;
+ }
+
+ lan743x_csr_write(adapter, MAC_TX, data | MAC_TX_TXEN_);
+
+done:
+ return 0;
+}
+
+static int lan743x_mac_tx_disable_all(struct lan743x_adapter *adapter)
+{
+ int ret = 0;
+ u32 data = 0;
+ int timeout = 100;
+
+ data = lan743x_csr_read(adapter, MAC_TX);
+ if (!(data & MAC_TX_TXEN_)) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempted to disable mac tx, when already disabled");
+ ret = 0;
+ goto done;
+ }
+ if (data & MAC_TX_TXD_) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "TXD unexpectedly set, clearing now");
+ lan743x_csr_write(adapter, MAC_TX, data);
+ data &= ~MAC_TX_TXD_;
+ }
+ data &= ~MAC_TX_TXEN_;
+ lan743x_csr_write(adapter, MAC_TX, data);
+ while (timeout &&
+ (!((data = lan743x_csr_read(adapter, MAC_TX)) & MAC_TX_TXD_))) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (!(data & MAC_TX_TXD_)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "timed out waiting for mac to disable tx");
+ ret = -EIO;
+ } else {
+ /* clear TXD */
+ lan743x_csr_write(adapter, MAC_TX, data);
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+static int lan743x_mac_tx_enable(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+ int ret = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+ mutex_lock(&mac->tx_mutex);
+ if (test_bit(tx_channel, &mac->tx_enable_bits)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "attempting to enable an already enabled tx channel = %d",
+ tx_channel);
+ goto done;
+ }
+ if (!mac->tx_enable_bits) {
+ ret = lan743x_mac_tx_enable_all(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to enable mac");
+ goto done;
+ }
+ }
+ mac->tx_enable_bits |= BIT(tx_channel);
+ ret = 0;
+done:
+ mutex_unlock(&mac->tx_mutex);
+ return ret;
+}
+
+static int lan743x_mac_tx_disable(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+ int ret = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+ mutex_lock(&mac->tx_mutex);
+ if (!(test_bit(tx_channel, &mac->tx_enable_bits))) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "attempting to disable an already disabled tx channel = %d",
+ tx_channel);
+ goto done;
+ }
+ mac->tx_enable_bits &= ~BIT(tx_channel);
+ if (!mac->tx_enable_bits) {
+ ret = lan743x_mac_tx_disable_all(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to disable mac");
+ goto done;
+ }
+ }
+ ret = 0;
+done:
+ mutex_unlock(&mac->tx_mutex);
+ return ret;
+}
+
+static int lan743x_mac_rx_enable_all(struct lan743x_adapter *adapter)
+{
+ u32 data = 0;
+
+ data = lan743x_csr_read(adapter, MAC_RX);
+ if (data & MAC_RX_RXEN_) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempted to enable mac rx, when already enabled");
+ goto done;
+ }
+
+ lan743x_csr_write(adapter, MAC_RX, data | MAC_RX_RXEN_);
+
+done:
+ return 0;
+}
+
+static int lan743x_mac_rx_disable_all(struct lan743x_adapter *adapter)
+{
+ int ret = 0;
+ u32 data = 0;
+ int timeout = 100;
+
+ data = lan743x_csr_read(adapter, MAC_RX);
+ if (!(data & MAC_RX_RXEN_)) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempted to disable mac rx, when already disabled");
+ ret = 0;
+ goto done;
+ }
+ if (data & MAC_RX_RXD_) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "RXD unexpectedly set, clearing now");
+ lan743x_csr_write(adapter, MAC_RX, data);
+ data &= ~MAC_RX_RXD_;
+ }
+ data &= ~MAC_RX_RXEN_;
+ lan743x_csr_write(adapter, MAC_RX, data);
+ while (timeout &&
+ (!((data = lan743x_csr_read(adapter, MAC_RX)) & MAC_RX_RXD_))) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (!(data & MAC_RX_RXD_)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "timed out waiting for mac to disable rx");
+ ret = -EIO;
+ } else {
+ /* clear RXD */
+ lan743x_csr_write(adapter, MAC_RX, data);
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+static int lan743x_mac_rx_enable(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+ int ret = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+ mutex_lock(&mac->rx_mutex);
+ if (test_bit(rx_channel, &mac->rx_enable_bits)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "attempting to enable an already enabled rx channel = %d",
+ rx_channel);
+ goto done;
+ }
+ if (!mac->rx_enable_bits) {
+ ret = lan743x_mac_rx_enable_all(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to enable mac");
+ goto done;
+ }
+ }
+ mac->rx_enable_bits |= BIT(rx_channel);
+ ret = 0;
+done:
+ mutex_unlock(&mac->rx_mutex);
+ return ret;
+}
+
+static int lan743x_mac_rx_disable(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+ int ret = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+ mutex_lock(&mac->rx_mutex);
+ if (!(test_bit(rx_channel, &mac->rx_enable_bits))) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "attempting to disable an already disabled rx channel = %d",
+ rx_channel);
+ goto done;
+ }
+ mac->rx_enable_bits &= ~BIT(rx_channel);
+ if (!mac->rx_enable_bits) {
+ ret = lan743x_mac_rx_disable_all(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to disable mac");
+ goto done;
+ }
+ }
+ ret = 0;
+done:
+ mutex_unlock(&mac->rx_mutex);
+ return ret;
+}
+
+static int lan743x_mac_set_mtu(struct lan743x_adapter *adapter, int new_mtu)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+ int ret = 0;
+ u32 mac_rx = 0;
+
+ if (new_mtu > LAN743X_MAX_FRAME_SIZE)
+ return -EINVAL;
+ if (new_mtu <= 0)
+ return -EINVAL;
+
+ mutex_lock(&mac->rx_mutex);
+ if (mac->rx_enable_bits) {
+ ret = lan743x_mac_rx_disable_all(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to disable mac");
+ goto done;
+ }
+ }
+
+ mac_rx = lan743x_csr_read(adapter, MAC_RX);
+ mac_rx &= ~(MAC_RX_MAX_SIZE_MASK_);
+ mac_rx |= (((new_mtu + ETH_HLEN + 4) << MAC_RX_MAX_SIZE_SHIFT_) &
+ MAC_RX_MAX_SIZE_MASK_);
+ lan743x_csr_write(adapter, MAC_RX, mac_rx);
+
+ if (mac->rx_enable_bits) {
+ ret = lan743x_mac_rx_enable_all(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to enable mac");
+ goto done;
+ }
+ }
+done:
+ mutex_unlock(&mac->rx_mutex);
+ return ret;
+}
+
+static struct net_device_stats *mac_get_stats(struct lan743x_adapter *adapter)
+{
+ struct lan743x_mac *mac = &adapter->mac;
+
+ memset(&mac->statistics, 0, sizeof(mac->statistics));
+ mac->statistics.rx_packets = lan743x_csr_read(adapter,
+ STAT_RX_TOTAL_FRAMES);
+ mac->statistics.tx_packets = lan743x_csr_read(adapter,
+ STAT_TX_TOTAL_FRAMES);
+ return &mac->statistics;
+}
+
+static void lan743x_mac_set_address(struct lan743x_adapter *adapter,
+ u8 *addr)
+{
+ u32 addr_lo, addr_hi;
+
+ addr_lo = addr[0] |
+ addr[1] << 8 |
+ addr[2] << 16 |
+ addr[3] << 24;
+ addr_hi = addr[4] |
+ addr[5] << 8;
+
+ lan743x_csr_write(adapter, MAC_RX_ADDRL, addr_lo);
+ lan743x_csr_write(adapter, MAC_RX_ADDRH, addr_hi);
+
+ ether_addr_copy(adapter->mac.mac_address, addr);
+
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "MAC address set to %02X:%02X:%02X:%02X:%02X:%02X",
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+}
+
+/* PHY */
+
+#define PHY_FLAG_OPENED BIT(0)
+#define PHY_FLAG_ATTACHED BIT(1)
+
+static int lan743x_phy_reset(struct lan743x_adapter *adapter)
+{
+ int ret = -EIO;
+ u32 data;
+ unsigned long timeout;
+
+ data = lan743x_csr_read(adapter, PMT_CTL);
+ data |= PMT_CTL_ETH_PHY_RST_;
+ lan743x_csr_write(adapter, PMT_CTL, data);
+
+ timeout = jiffies + HZ;
+
+ do {
+ if (time_after(jiffies, timeout)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "timeout, incomplete phy reset");
+ ret = -EIO;
+ goto done;
+ }
+ msleep(50);
+ data = lan743x_csr_read(adapter, PMT_CTL);
+ } while ((data & PMT_CTL_ETH_PHY_RST_) || !(data & PMT_CTL_READY_));
+
+ ret = 0;
+done:
+ return ret;
+}
+
+static void lan743x_phy_update_flowcontrol(struct lan743x_adapter *adapter,
+ u8 duplex, u16 local_adv,
+ u16 remote_adv)
+{
+ struct lan743x_phy *phy = &adapter->phy;
+ u8 cap;
+
+ if (phy->fc_autoneg)
+ cap = mii_resolve_flowctrl_fdx(local_adv, remote_adv);
+ else
+ cap = phy->fc_request_control;
+
+ lan743x_mac_flow_ctrl_set_enables(adapter,
+ cap & FLOW_CTRL_TX,
+ cap & FLOW_CTRL_RX);
+
+ NETIF_INFO(adapter, drv, adapter->netdev, "rx pause %s, tx pause %s",
+ (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
+ (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+}
+
+static int lan743x_phy_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_phy *phy = &adapter->phy;
+ int ret = -ENODEV;
+ struct net_device *netdev;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, phy);
+
+ netdev = adapter->netdev;
+
+ memset(phy, 0, sizeof(struct lan743x_phy));
+
+ ret = lan743x_phy_reset(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "phy reset failed, ret = %d", ret);
+ goto clean_up;
+ }
+
+ /* carrier off reporting is important to ethtool even BEFORE open */
+ netif_carrier_off(netdev);
+
+ ret = 0;
+
+clean_up:
+ if (ret)
+ lan743x_phy_cleanup(adapter);
+ return ret;
+}
+
+static void lan743x_phy_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_phy *phy = &adapter->phy;
+
+ memset(phy, 0, sizeof(struct lan743x_phy));
+}
+
+static void lan743x_phy_link_status_change(struct net_device *netdev)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ struct phy_device *phydev = netdev->phydev;
+
+ if (phydev) {
+ if (phydev->state == PHY_RUNNING) {
+ struct ethtool_link_ksettings ksettings;
+ int local_advertisement = 0;
+ int remote_advertisement = 0;
+ struct lan743x_phy *phy = NULL;
+
+ NETIF_ASSERT(adapter, link, adapter->netdev, adapter);
+ phy = &adapter->phy;
+
+ memset(&ksettings, 0, sizeof(ksettings));
+ phy_ethtool_get_link_ksettings(netdev, &ksettings);
+
+ local_advertisement = phy_read(phydev, MII_ADVERTISE);
+ if (local_advertisement < 0) {
+ NETIF_ERROR(adapter, link, adapter->netdev,
+ "reading local_advertisement failed");
+ goto done;
+ }
+
+ remote_advertisement = phy_read(phydev, MII_LPA);
+ if (remote_advertisement < 0) {
+ NETIF_ERROR(adapter, link, adapter->netdev,
+ "reading remote_advertisement failed");
+ goto done;
+ }
+
+ NETIF_INFO(adapter, link, adapter->netdev,
+ "link UP: speed: %u duplex: %d anadv: 0x%04x anlpa: 0x%04x",
+ ksettings.base.speed, ksettings.base.duplex,
+ local_advertisement, remote_advertisement);
+
+ lan743x_phy_update_flowcontrol(adapter,
+ ksettings.base.duplex,
+ local_advertisement,
+ remote_advertisement);
+ } else if (phydev->state == PHY_NOLINK) {
+ NETIF_INFO(adapter, link, adapter->netdev,
+ "link DOWN");
+ }
+ } else {
+ NETIF_ERROR(adapter, link, adapter->netdev, "phydev == NULL");
+ }
+done:
+ return;
+}
+
+static int lan743x_phy_open(struct lan743x_adapter *adapter)
+{
+ struct lan743x_phy *phy = &adapter->phy;
+ int ret;
+ u32 mii_adv;
+ struct phy_device *phydev;
+ struct net_device *netdev;
+ struct lan743x_mac *mac = &adapter->mac;
+ int phy_id1 = 0;
+ int phy_id2 = 0;
+
+ netdev = adapter->netdev;
+
+ NETIF_ASSERT(adapter, ifup, adapter->netdev, mac->mdiobus);
+
+ phydev = phy_find_first(mac->mdiobus);
+ if (!phydev) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev, "no PHY found");
+ ret = -EIO;
+ goto clean_up;
+ }
+
+ phydev->irq = PHY_POLL;
+
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "phy irq assigned to %d", phydev->irq);
+ ret = phy_connect_direct(netdev, phydev,
+ lan743x_phy_link_status_change,
+ PHY_INTERFACE_MODE_GMII);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "can't attach PHY to %s", mac->mdiobus->id);
+ ret = -EIO;
+ goto clean_up;
+ }
+ phy->flags |= PHY_FLAG_ATTACHED;
+
+ if (!(phydev->drv)) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Missing PHY Driver");
+ ret = -EIO;
+ goto clean_up;
+ }
+
+ phy_id1 = phy_read(phydev, MII_PHYSID1);
+ phy_id2 = phy_read(phydev, MII_PHYSID2);
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "PHY_ID1 = 0x%04x", phy_id1);
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "PHY_ID2 = 0x%04x", phy_id2);
+
+ /* MAC doesn't support 1000T Half */
+ phydev->supported &= ~SUPPORTED_1000baseT_Half;
+
+ /* support both flow controls */
+ phy->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
+ phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+ mii_adv = (u32)mii_advertise_flowctrl(phy->fc_request_control);
+ phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
+
+ phy->fc_autoneg = phydev->autoneg;
+
+ /* PHY interrupt enabled here */
+ phy_start(phydev);
+
+ phy_start_aneg(phydev);
+
+ phy->flags |= PHY_FLAG_OPENED;
+ ret = 0;
+
+clean_up:
+ if (ret)
+ lan743x_phy_close(adapter);
+ return ret;
+}
+
+static void lan743x_phy_close(struct lan743x_adapter *adapter)
+{
+ struct lan743x_phy *phy = &adapter->phy;
+ struct net_device *netdev = adapter->netdev;
+
+ if (phy->flags & PHY_FLAG_OPENED) {
+ netif_carrier_off(netdev);
+
+ phy_stop(netdev->phydev);
+ phy->flags &= ~PHY_FLAG_OPENED;
+ }
+ if (phy->flags & PHY_FLAG_ATTACHED) {
+ phy_disconnect(netdev->phydev);
+ netdev->phydev = NULL;
+ phy->flags &= ~PHY_FLAG_ATTACHED;
+ }
+}
+
+/* RFE */
+
+static void lan743x_rfe_update_mac_address(struct lan743x_adapter *adapter)
+{
+ u8 mac_addr[ETH_ALEN];
+ u32 mac_addr_hi = 0;
+ u32 mac_addr_lo = 0;
+
+ /* Add mac address to perfect Filter */
+ lan743x_mac_get_address(adapter, mac_addr);
+ mac_addr_lo = ((((u32)(mac_addr[0])) << 0) |
+ (((u32)(mac_addr[1])) << 8) |
+ (((u32)(mac_addr[2])) << 16) |
+ (((u32)(mac_addr[3])) << 24));
+ mac_addr_hi = ((((u32)(mac_addr[4])) << 0) |
+ (((u32)(mac_addr[5])) << 8));
+ lan743x_csr_write(adapter, RFE_ADDR_FILT_LO(0), mac_addr_lo);
+ lan743x_csr_write(adapter, RFE_ADDR_FILT_HI(0),
+ mac_addr_hi | RFE_ADDR_FILT_HI_VALID_);
+}
+
+static int lan743x_rfe_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_rfe *rfe = &adapter->rfe;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, rfe);
+ memset(rfe, 0, sizeof(*rfe));
+
+ /* Add mac address to perfect Filter */
+ lan743x_rfe_update_mac_address(adapter);
+
+ return 0;
+}
+
+static void lan743x_rfe_cleanup(struct lan743x_adapter *adapter)
+{
+ /* This empty function is kept as a place holder */
+}
+
+static int lan743x_rfe_open(struct lan743x_adapter *adapter)
+{
+ /* This empty function is kept as a place holder */
+ return 0;
+}
+
+static void lan743x_rfe_close(struct lan743x_adapter *adapter)
+{
+ /* This empty function is kept as a place holder */
+}
+
+/* returns hash bit number for given MAC address */
+static inline u32 lan743x_rfe_get_hash_bit(char addr[ETH_ALEN])
+{
+ return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff;
+}
+
+static void lan743x_rfe_set_multicast(struct lan743x_adapter *adapter)
+{
+ u32 rfctl;
+ u32 data;
+ struct net_device *netdev = adapter->netdev;
+ u32 hash_table[DP_SEL_VHF_HASH_LEN];
+
+ rfctl = lan743x_csr_read(adapter, RFE_CTL);
+
+ rfctl &= ~(RFE_CTL_AU_ | RFE_CTL_AM_ |
+ RFE_CTL_DA_PERFECT_ | RFE_CTL_MCAST_HASH_);
+
+ rfctl |= RFE_CTL_AB_;
+
+ if (netdev->flags & IFF_PROMISC) {
+ rfctl |= RFE_CTL_AM_ | RFE_CTL_AU_;
+ } else {
+ if (netdev->flags & IFF_ALLMULTI)
+ rfctl |= RFE_CTL_AM_;
+ }
+
+ memset(hash_table, 0, DP_SEL_VHF_HASH_LEN * sizeof(u32));
+
+ if (netdev_mc_count(netdev)) {
+ struct netdev_hw_addr *ha;
+ int i;
+
+ rfctl |= RFE_CTL_DA_PERFECT_;
+
+ i = 1;
+ netdev_for_each_mc_addr(ha, netdev) {
+ /* set first 32 into Perfect Filter */
+ if (i < 33) {
+ lan743x_csr_write(adapter,
+ RFE_ADDR_FILT_HI(i), 0);
+ data = ha->addr[3];
+ data = ha->addr[2] | (data << 8);
+ data = ha->addr[1] | (data << 8);
+ data = ha->addr[0] | (data << 8);
+ lan743x_csr_write(adapter,
+ RFE_ADDR_FILT_LO(i), data);
+ data = ha->addr[5];
+ data = ha->addr[4] | (data << 8);
+ data |= RFE_ADDR_FILT_HI_VALID_;
+ lan743x_csr_write(adapter,
+ RFE_ADDR_FILT_HI(i), data);
+ } else {
+ u32 bitnum = lan743x_rfe_get_hash_bit(ha->addr);
+
+ hash_table[bitnum / 32] |= (1 << (bitnum % 32));
+ rfctl |= RFE_CTL_MCAST_HASH_;
+ }
+ i++;
+ }
+ }
+
+ if (lan743x_dp_write_hash_filter(adapter, hash_table))
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "write to hash table failed");
+
+ lan743x_csr_write(adapter, RFE_CTL, rfctl);
+}
+
+/* FCT */
+
+static void lan743x_fct_isr(void *context)
+{
+ struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+ u32 fct_int_sts = 0;
+ u32 fct_int_en = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_FCT_);
+
+ fct_int_sts = lan743x_csr_read(adapter, FCT_INT_STS);
+ fct_int_en = lan743x_csr_read(adapter, FCT_INT_EN_SET);
+
+ fct_int_sts = fct_int_sts & fct_int_en;
+ if (fct_int_sts & FCT_INT_MASK_ERRORS_) {
+ if (fct_int_sts & FCT_INT_BIT_TXE_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Transmitter Error");
+ if (fct_int_sts & FCT_INT_BIT_TDFO_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Tx Data FIFO Overrun");
+ if (fct_int_sts & FCT_INT_BIT_TDFU_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "TX Data FIFO Underrun");
+ }
+ if (fct_int_sts & (~FCT_INT_MASK_ERRORS_))
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "unhandled interrupt, fct_int_sts = 0x%08X",
+ fct_int_sts);
+
+ /* clear fct int status bits */
+ lan743x_csr_write(adapter, FCT_INT_STS, fct_int_sts);
+
+ /* enable isr */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_FCT_);
+}
+
+static int lan743x_fct_init(struct lan743x_adapter *adapter)
+{
+ /* this empty function is kept as a place holder */
+ return 0;
+}
+
+static void lan743x_fct_cleanup(struct lan743x_adapter *adapter)
+{
+ /* this empty function is kept as a place holder */
+}
+
+static int lan743x_fct_open(struct lan743x_adapter *adapter)
+{
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_FCT_);
+ lan743x_csr_write(adapter, FCT_INT_EN_SET, FCT_INT_MASK_ERRORS_);
+ return 0;
+}
+
+static void lan743x_fct_close(struct lan743x_adapter *adapter)
+{
+ lan743x_csr_write(adapter, FCT_INT_EN_CLR, FCT_INT_MASK_ERRORS_);
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_FCT_);
+}
+
+static int lan743x_fct_rx_reset(struct lan743x_adapter *adapter, int rx_channel)
+{
+ int ret = -EIO;
+ int timeout = 100;
+ u32 data = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+
+ data = lan743x_csr_read(adapter, FCT_RX_CTL);
+ if (data & FCT_RX_CTL_EN_(rx_channel)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Attempting to reset fifo while enabled, rx_channel = %d",
+ rx_channel);
+ ret = -EIO;
+ goto done;
+ }
+
+ lan743x_csr_write(adapter, FCT_RX_CTL, FCT_RX_CTL_RESET_(rx_channel));
+ while (timeout &&
+ ((data = lan743x_csr_read(adapter, FCT_RX_CTL)) &
+ FCT_RX_CTL_RESET_(rx_channel))) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data & FCT_RX_CTL_RESET_(rx_channel)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for rx fifo to reset, rx_channel = %d",
+ rx_channel);
+ ret = -EIO;
+ goto done;
+ }
+
+ lan743x_csr_write(adapter, FCT_FLOW(rx_channel),
+ FCT_FLOW_CTL_REQ_EN_ |
+ FCT_FLOW_CTL_ON_THRESHOLD_SET_(0x2A) |
+ FCT_FLOW_CTL_OFF_THRESHOLD_SET_(0xA));
+
+ ret = 0;
+done:
+ return ret;
+}
+
+static int lan743x_fct_rx_enable(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ u32 data = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+
+ data = lan743x_csr_read(adapter, FCT_RX_CTL);
+ if (data & FCT_RX_CTL_EN_(rx_channel)) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempting to enable an already enabled channel, rx_channel = %d",
+ rx_channel);
+ } else {
+ lan743x_csr_write(adapter, FCT_RX_CTL,
+ FCT_RX_CTL_EN_(rx_channel));
+ }
+
+ return 0;
+}
+
+static int lan743x_fct_rx_disable(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ int ret = -EIO;
+ int timeout = 100;
+ u32 data = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+
+ data = lan743x_csr_read(adapter, FCT_RX_CTL);
+ if (!(data & FCT_RX_CTL_EN_(rx_channel))) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempting to disable an already disabled channel, rx_channel = %d",
+ rx_channel);
+ ret = 0;
+ goto done;
+ } else {
+ lan743x_csr_write(adapter, FCT_RX_CTL,
+ FCT_RX_CTL_DIS_(rx_channel));
+ }
+
+ while (timeout &&
+ ((data = lan743x_csr_read(adapter, FCT_RX_CTL)) &
+ FCT_RX_CTL_EN_(rx_channel))) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data & FCT_RX_CTL_EN_(rx_channel)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for rx fifo to disable, rx_channel = %d",
+ rx_channel);
+ ret = -EIO;
+ goto done;
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+static int lan743x_fct_tx_reset(struct lan743x_adapter *adapter, int tx_channel)
+{
+ int ret = -EIO;
+ int timeout = 100;
+ u32 data = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+
+ data = lan743x_csr_read(adapter, FCT_TX_CTL);
+ if (data & FCT_TX_CTL_EN_(tx_channel)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Attempting to reset fifo while enabled, tx_channel = %d",
+ tx_channel);
+ ret = -EIO;
+ goto done;
+ }
+
+ lan743x_csr_write(adapter, FCT_TX_CTL, FCT_TX_CTL_RESET_(tx_channel));
+ while (timeout &&
+ ((data = lan743x_csr_read(adapter, FCT_TX_CTL)) &
+ FCT_TX_CTL_RESET_(tx_channel))) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data & FCT_TX_CTL_RESET_(tx_channel)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for tx fifo to reset, tx_channel = %d",
+ tx_channel);
+ ret = -EIO;
+ goto done;
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+static int lan743x_fct_tx_enable(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ u32 data = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+
+ data = lan743x_csr_read(adapter, FCT_TX_CTL);
+ if (data & FCT_TX_CTL_EN_(tx_channel)) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempting to enable an already enabled channel, tx_channel = %d",
+ tx_channel);
+ } else {
+ lan743x_csr_write(adapter, FCT_TX_CTL,
+ FCT_TX_CTL_EN_(tx_channel));
+ }
+
+ return 0;
+}
+
+static int lan743x_fct_tx_disable(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ int ret = -EIO;
+ int timeout = 100;
+ u32 data = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+
+ data = lan743x_csr_read(adapter, FCT_TX_CTL);
+ if (!(data & FCT_TX_CTL_EN_(tx_channel))) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempting to disable an already disabled channel, tx_channel = %d",
+ tx_channel);
+ ret = 0;
+ goto done;
+ } else {
+ lan743x_csr_write(adapter, FCT_TX_CTL,
+ FCT_TX_CTL_DIS_(tx_channel));
+ }
+
+ while (timeout &&
+ ((data = lan743x_csr_read(adapter, FCT_TX_CTL)) &
+ FCT_TX_CTL_EN_(tx_channel))) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data & FCT_TX_CTL_EN_(tx_channel)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for tx fifo to disable, tx_channel = %d",
+ tx_channel);
+ ret = -EIO;
+ goto done;
+ }
+ ret = 0;
+done:
+ return ret;
+}
+
+/* DMAC */
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+#define DMA_ADDR_HIGH32(dma_addr) ((u32)(((dma_addr) >> 32) & 0xFFFFFFFF))
+#else
+#define DMA_ADDR_HIGH32(dma_addr) ((u32)(0))
+#endif
+#define DMA_ADDR_LOW32(dma_addr) ((u32)((dma_addr) & 0xFFFFFFFF))
+
+#define DMAC_FLAG_TX_USED(channel) BIT(0 + (channel))
+#define DMAC_FLAG_TX0_USED BIT(0)
+#define DMAC_FLAG_TX1_USED BIT(1)
+#define DMAC_FLAG_TX2_USED BIT(2)
+#define DMAC_FLAG_TX3_USED BIT(3)
+#define DMAC_FLAG_RX_USED(channel) BIT(4 + (channel))
+#define DMAC_FLAG_RX0_USED BIT(4)
+#define DMAC_FLAG_RX1_USED BIT(5)
+#define DMAC_FLAG_RX2_USED BIT(6)
+#define DMAC_FLAG_RX3_USED BIT(7)
+
+#define DMA_DESCRIPTOR_SPACING_16 (16)
+#define DMA_DESCRIPTOR_SPACING_32 (32)
+#define DMA_DESCRIPTOR_SPACING_64 (64)
+#define DMA_DESCRIPTOR_SPACING_128 (128)
+
+#define DEFAULT_DMA_DESCRIPTOR_SPACING (L1_CACHE_BYTES)
+
+static void lan743x_dmac_isr(void *context)
+{
+ struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+ struct lan743x_dmac *dmac = NULL;
+ u32 dmac_int_sts = 0;
+ int channel = 0;
+ int found_set_bit = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, adapter);
+ dmac = &adapter->dmac;
+
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_DMA_GEN_);
+
+ dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS);
+
+ if (!(dmac_int_sts & DMAC_INT_BIT_ERR_)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "unexpected dmac_isr call");
+ goto done;
+ }
+
+ for (channel = 0; channel < LAN743X_NUMBER_OF_RX_CHANNELS;
+ channel++) {
+ u32 rx_err_sts = lan743x_csr_read(adapter,
+ DMAC_RX_ERR_STS(channel));
+
+ if (rx_err_sts &
+ (DMAC_RX_ERR_STS_RESERVED_ |
+ DMAC_RX_ERR_STS_RX_DESC_READ_ERR_ |
+ DMAC_RX_ERR_STS_RX_DESC_TAIL_ERR_)) {
+ found_set_bit = 1;
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "RX_ERR_STS(%d) = 0x%08X",
+ channel, rx_err_sts);
+ if (rx_err_sts & DMAC_RX_ERR_STS_RESERVED_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " reserved bits set");
+ if (rx_err_sts &
+ DMAC_RX_ERR_STS_RX_DESC_READ_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " RX Descriptor Read Retry Error");
+ if (rx_err_sts &
+ DMAC_RX_ERR_STS_RX_DESC_TAIL_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " RX Descriptor Tail Error");
+
+ /* clear errors */
+ lan743x_csr_write(adapter, DMAC_RX_ERR_STS(channel),
+ rx_err_sts);
+ }
+ }
+ for (channel = 0;
+ channel < LAN743X_NUMBER_OF_TX_CHANNELS; channel++) {
+ u32 tx_err_sts = lan743x_csr_read(adapter,
+ DMAC_TX_ERR_STS(channel));
+
+ if (tx_err_sts &
+ (DMAC_TX_ERR_STS_RESERVED_ |
+ DMAC_TX_ERR_STS_TX_DATA_READ_ERR_ |
+ DMAC_TX_ERR_STS_TX_DESC_READ_ERR_ |
+ DMAC_TX_ERR_STS_TX_DESC_TAIL_ERR_ |
+ DMAC_TX_ERR_STS_TX_FCT_TXE_ |
+ DMAC_TX_ERR_STS_TX_DESC_DATATYPE_ERR_ |
+ DMAC_TX_ERR_STS_TX_DESC_EXTNTYPE_ERR_ |
+ DMAC_TX_ERR_STS_TX_DESC_EXTRAFS_ERR_ |
+ DMAC_TX_ERR_STS_TX_DESC_NOFS_ERR_)) {
+ found_set_bit = 1;
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "TX_ERR_STS(%d) = 0x%08X",
+ channel, tx_err_sts);
+ if (tx_err_sts & DMAC_TX_ERR_STS_RESERVED_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " reserved bits set");
+ if (tx_err_sts &
+ DMAC_TX_ERR_STS_TX_DATA_READ_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " TX Data Buffer Read Retry Error");
+ if (tx_err_sts &
+ DMAC_TX_ERR_STS_TX_DESC_READ_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " TX Descriptor Read Retry Error");
+ if (tx_err_sts &
+ DMAC_TX_ERR_STS_TX_DESC_TAIL_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " TX Descriptor Tail Error");
+ if (tx_err_sts & DMAC_TX_ERR_STS_TX_FCT_TXE_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " TX FCT TX Error");
+ if (tx_err_sts &
+ DMAC_TX_ERR_STS_TX_DESC_DATATYPE_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " TX Data Descriptor Missing Error");
+ if (tx_err_sts &
+ DMAC_TX_ERR_STS_TX_DESC_EXTNTYPE_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " TX Extension Descriptor Missing Error");
+ if (tx_err_sts &
+ DMAC_TX_ERR_STS_TX_DESC_EXTRAFS_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " TX Descriptor Extraneous FS Error");
+ if (tx_err_sts &
+ DMAC_TX_ERR_STS_TX_DESC_NOFS_ERR_)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ " TX Descriptor Missing FS Error");
+
+ /* clear errors */
+ lan743x_csr_write(adapter, DMAC_TX_ERR_STS(channel),
+ tx_err_sts);
+ }
+ }
+ if (!found_set_bit)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "DMAC_INT_BIT_ERR_ set with out cause, DMAC_INT_STS = 0x%08X",
+ dmac_int_sts);
+done:
+ /* clear dma int status */
+ lan743x_csr_write(adapter, DMAC_INT_STS, dmac_int_sts);
+
+ /* enable isr */
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_DMA_GEN_);
+}
+
+static int lan743x_dmac_reset(struct lan743x_adapter *adapter)
+{
+ int timeout = 100;
+ u32 data = 0;
+ int ret = 0;
+
+ lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_SWR_);
+ while (timeout &&
+ ((data = lan743x_csr_read(adapter, DMAC_CMD)) &
+ DMAC_CMD_SWR_)) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data & DMAC_CMD_SWR_) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for DMAC reset to complete");
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+static int lan743x_dmac_init(struct lan743x_adapter *adapter)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = -ENODEV;
+ u32 dma_cfg = 0;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, dmac);
+
+ memset(dmac, 0, sizeof(*dmac));
+
+ dmac->flags = 0;
+
+ dmac->descriptor_spacing = DEFAULT_DMA_DESCRIPTOR_SPACING;
+
+ ret = lan743x_dmac_reset(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "DMAC reset failed");
+ goto cleanup;
+ }
+
+ switch (dmac->descriptor_spacing) {
+ case DMA_DESCRIPTOR_SPACING_16:
+ dma_cfg = DMAC_CFG_MAX_DSPACE_16_;
+ break;
+ case DMA_DESCRIPTOR_SPACING_32:
+ dma_cfg = DMAC_CFG_MAX_DSPACE_32_;
+ break;
+ case DMA_DESCRIPTOR_SPACING_64:
+ dma_cfg = DMAC_CFG_MAX_DSPACE_64_;
+ break;
+ case DMA_DESCRIPTOR_SPACING_128:
+ dma_cfg = DMAC_CFG_MAX_DSPACE_128_;
+ break;
+ default:
+ ret = -EPERM;
+ goto cleanup;
+ }
+ dma_cfg |= DMAC_CFG_CH_ARB_SEL_RX_HIGH_;
+ dma_cfg |= DMAC_CFG_MAX_READ_REQ_SET_(6);
+ lan743x_csr_write(adapter, DMAC_CFG, dma_cfg);
+
+ ret = 0;
+cleanup:
+ if (ret)
+ lan743x_dmac_cleanup(adapter);
+ return ret;
+}
+
+static void lan743x_dmac_cleanup(struct lan743x_adapter *adapter)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int channel;
+
+ /* error checking */
+ for (channel = 0; channel < LAN743X_NUMBER_OF_TX_CHANNELS;
+ channel++) {
+ if (dmac->flags & (DMAC_FLAG_TX_USED(channel))) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "TX Channel %d, is still in use",
+ channel);
+ }
+ }
+ for (channel = 0; channel < LAN743X_NUMBER_OF_RX_CHANNELS;
+ channel++) {
+ if (dmac->flags & (DMAC_FLAG_RX_USED(channel))) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "RX Channel %d, is still in use",
+ channel);
+ }
+ }
+
+ memset(dmac, 0, sizeof(*dmac));
+}
+
+static int lan743x_dmac_open(struct lan743x_adapter *adapter)
+{
+ lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_DMA_GEN_);
+ lan743x_csr_write(adapter, DMAC_INT_EN_SET, DMAC_INT_BIT_ERR_);
+
+ return 0;
+}
+
+static void lan743x_dmac_close(struct lan743x_adapter *adapter)
+{
+ lan743x_csr_write(adapter, DMAC_INT_EN_CLR, DMAC_INT_BIT_ERR_);
+ lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_DMA_GEN_);
+}
+
+static int lan743x_dmac_get_descriptor_spacing(struct lan743x_adapter *adapter)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+
+ return dmac->descriptor_spacing;
+}
+
+static int lan743x_dmac_reserve_tx_channel(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = -EBUSY;
+
+ if ((tx_channel >= 0) && (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS)) {
+ if (!(dmac->flags & DMAC_FLAG_TX_USED(tx_channel))) {
+ /* tx channel not yet used, go ahead and reserve it */
+ dmac->flags |= DMAC_FLAG_TX_USED(tx_channel);
+ ret = 0;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Attempted to reserve a channel that was already reserved, tx_channel = %d",
+ tx_channel);
+ }
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "out of range, channel_number = %d",
+ tx_channel);
+ }
+ return ret;
+}
+
+static void lan743x_dmac_release_tx_channel(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+
+ if ((tx_channel >= 0) && (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS)) {
+ if (dmac->flags & DMAC_FLAG_TX_USED(tx_channel)) {
+ /* tx channel is in use, go ahead and release it */
+ dmac->flags &= ~DMAC_FLAG_TX_USED(tx_channel);
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Attempted to release a tx channel that was not in use, tx_channel = %d",
+ tx_channel);
+ }
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "out of range, tx_channel = %d",
+ tx_channel);
+ }
+}
+
+static int lan743x_dmac_reserve_rx_channel(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = -EBUSY;
+
+ if ((rx_channel >= 0) && (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS)) {
+ if (!(dmac->flags & DMAC_FLAG_RX_USED(rx_channel))) {
+ /* rx channel not yet used, go ahead and reserve it */
+ dmac->flags |= DMAC_FLAG_RX_USED(rx_channel);
+ ret = 0;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Attempted to reserve an rx channel that was already reserved, rx_channel = %d",
+ rx_channel);
+ }
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "out of range, rx_channel = %d", rx_channel);
+ }
+ return ret;
+}
+
+static void lan743x_dmac_release_rx_channel(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+
+ if ((rx_channel >= 0) && (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS)) {
+ if (dmac->flags & DMAC_FLAG_RX_USED(rx_channel)) {
+ /* rx channel is in use, go ahead and release it */
+ dmac->flags &= ~DMAC_FLAG_RX_USED(rx_channel);
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Attempted to release an rx channel that was not in use, rx_channel = %d",
+ rx_channel);
+ }
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "out of range, rx_channel = %d", rx_channel);
+ }
+}
+
+#define DMAC_CHANNEL_STATE_SET(start_bit, stop_bit) \
+ (((start_bit) ? 2 : 0) | ((stop_bit) ? 1 : 0))
+#define DMAC_CHANNEL_STATE_INITIAL DMAC_CHANNEL_STATE_SET(0, 0)
+#define DMAC_CHANNEL_STATE_STARTED DMAC_CHANNEL_STATE_SET(1, 0)
+#define DMAC_CHANNEL_STATE_STOP_PENDING DMAC_CHANNEL_STATE_SET(1, 1)
+#define DMAC_CHANNEL_STATE_STOPPED DMAC_CHANNEL_STATE_SET(0, 1)
+
+static int lan743x_dmac_tx_reset(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = 0;
+ int timeout = 100;
+ u32 data = 0;
+ u32 reset_bit = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ dmac->flags & DMAC_FLAG_TX_USED(tx_channel));
+
+ reset_bit = DMAC_CMD_TX_SWR_(tx_channel);
+
+ lan743x_csr_write(adapter, DMAC_CMD, reset_bit);
+ while (timeout &&
+ ((data = lan743x_csr_read(adapter, DMAC_CMD)) & reset_bit)) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data & reset_bit) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for TX channel %d reset to complete",
+ tx_channel);
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+static int lan743x_dmac_tx_get_state(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ u32 dmac_cmd = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ dmac->flags & DMAC_FLAG_TX_USED(tx_channel));
+
+ dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD);
+ return DMAC_CHANNEL_STATE_SET((dmac_cmd &
+ DMAC_CMD_START_T_(tx_channel)),
+ (dmac_cmd &
+ DMAC_CMD_STOP_T_(tx_channel)));
+}
+
+static int lan743x_dmac_tx_wait_till_stopped(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ int result = 0;
+ int timeout = 100;
+
+ while (timeout &&
+ ((result = lan743x_dmac_tx_get_state(adapter, tx_channel)) ==
+ DMAC_CHANNEL_STATE_STOP_PENDING)) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (result == DMAC_CHANNEL_STATE_STOP_PENDING) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for tx channel %d to stop",
+ tx_channel);
+ result = -ENODEV;
+ }
+ return result;
+}
+
+static int lan743x_dmac_tx_start(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = 0;
+ int state = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ dmac->flags & DMAC_FLAG_TX_USED(tx_channel));
+
+ state = lan743x_dmac_tx_wait_till_stopped(adapter, tx_channel);
+ if (state < 0) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "failed wait till not stop pending, tx_channel = %d",
+ tx_channel);
+ ret = -ENODEV;
+ goto done;
+ }
+ if (state != DMAC_CHANNEL_STATE_STARTED) {
+ lan743x_csr_write(adapter, DMAC_CMD,
+ DMAC_CMD_START_T_(tx_channel));
+ state = lan743x_dmac_tx_get_state(adapter, tx_channel);
+ if (state != DMAC_CHANNEL_STATE_STARTED) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to start tx channel %d",
+ tx_channel);
+ ret = -ENODEV;
+ goto done;
+ }
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempting to start an already started tx_channel = %d",
+ tx_channel);
+ }
+done:
+ return ret;
+}
+
+static int lan743x_dmac_tx_stop(struct lan743x_adapter *adapter,
+ int tx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = 0;
+ int state = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ dmac->flags & DMAC_FLAG_TX_USED(tx_channel));
+
+ state = lan743x_dmac_tx_get_state(adapter, tx_channel);
+ if (state == DMAC_CHANNEL_STATE_STARTED) {
+ lan743x_csr_write(adapter,
+ DMAC_CMD, DMAC_CMD_STOP_T_(tx_channel));
+ state = lan743x_dmac_tx_wait_till_stopped(
+ adapter, tx_channel);
+ if (state < 0) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "failed wait till not stop pending, tx_channel = %d",
+ tx_channel);
+ ret = -ENODEV;
+ }
+ } else if (state == DMAC_CHANNEL_STATE_STOP_PENDING) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "A stop is already pending for tx_channel = %d",
+ tx_channel);
+ state = lan743x_dmac_tx_wait_till_stopped(
+ adapter, tx_channel);
+ if (state < 0) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "failed wait till not stop pending, tx_channel = %d",
+ tx_channel);
+ ret = -ENODEV;
+ }
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempting to stop a not started tx channel = %d",
+ tx_channel);
+ }
+ return ret;
+}
+
+static int lan743x_dmac_rx_get_state(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ u32 dmac_cmd = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ dmac->flags & DMAC_FLAG_RX_USED(rx_channel));
+
+ dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD);
+ return DMAC_CHANNEL_STATE_SET((dmac_cmd &
+ DMAC_CMD_START_R_(rx_channel)),
+ (dmac_cmd &
+ DMAC_CMD_STOP_R_(rx_channel)));
+}
+
+static int lan743x_dmac_rx_wait_till_stopped(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ int result = 0;
+ int timeout = 100;
+
+ while (timeout &&
+ ((result = lan743x_dmac_rx_get_state(adapter, rx_channel)) ==
+ DMAC_CHANNEL_STATE_STOP_PENDING)) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (result == DMAC_CHANNEL_STATE_STOP_PENDING) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for rx channel %d to stop",
+ rx_channel);
+ result = -ENODEV;
+ }
+ return result;
+}
+
+static int lan743x_dmac_rx_reset(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = 0;
+ int timeout = 100;
+ u32 data = 0;
+ u32 reset_bit = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ dmac->flags & DMAC_FLAG_RX_USED(rx_channel));
+
+ reset_bit = DMAC_CMD_RX_SWR_(rx_channel);
+
+ lan743x_csr_write(adapter, DMAC_CMD, reset_bit);
+ while (timeout &&
+ ((data = lan743x_csr_read(adapter, DMAC_CMD)) & reset_bit)) {
+ usleep_range(1000, 20000);
+ timeout--;
+ }
+ if (data & reset_bit) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Timed out waiting for RX channel %d reset to complete",
+ rx_channel);
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+static int lan743x_dmac_rx_start(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = 0;
+ int state = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ dmac->flags & DMAC_FLAG_RX_USED(rx_channel));
+
+ state = lan743x_dmac_rx_wait_till_stopped(adapter, rx_channel);
+ if (state < 0) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "failed wait till not stop pending, rx_channel = %d",
+ rx_channel);
+ ret = -ENODEV;
+ goto done;
+ }
+ if (state != DMAC_CHANNEL_STATE_STARTED) {
+ lan743x_csr_write(adapter, DMAC_CMD,
+ DMAC_CMD_START_R_(rx_channel));
+ state = lan743x_dmac_rx_get_state(adapter, rx_channel);
+ if (state != DMAC_CHANNEL_STATE_STARTED) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to start rx channel %d",
+ rx_channel);
+ ret = -ENODEV;
+ goto done;
+ }
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempting to start an already started rx_channel = %d",
+ rx_channel);
+ }
+done:
+ return ret;
+}
+
+static int lan743x_dmac_rx_stop(struct lan743x_adapter *adapter,
+ int rx_channel)
+{
+ struct lan743x_dmac *dmac = &adapter->dmac;
+ int ret = 0;
+ int state = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ dmac->flags & DMAC_FLAG_RX_USED(rx_channel));
+
+ state = lan743x_dmac_rx_get_state(adapter, rx_channel);
+ if (state == DMAC_CHANNEL_STATE_STARTED) {
+ lan743x_csr_write(adapter, DMAC_CMD,
+ DMAC_CMD_STOP_R_(rx_channel));
+ state = lan743x_dmac_rx_wait_till_stopped(adapter, rx_channel);
+ if (state < 0) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "failed wait till not stop pending, rx_channel = %d",
+ rx_channel);
+ ret = -ENODEV;
+ }
+ } else if (state == DMAC_CHANNEL_STATE_STOP_PENDING) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "A stop is already pending for rx_channel = %d",
+ rx_channel);
+ state = lan743x_dmac_rx_wait_till_stopped(adapter, rx_channel);
+ if (state < 0) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "failed wait till not stop pending, rx_channel = %d",
+ rx_channel);
+ ret = -ENODEV;
+ }
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Attempting to stop a not started rx channel = %d",
+ rx_channel);
+ }
+ return ret;
+}
+
+/* TX */
+
+/* TX Descriptor bits */
+#define TX_DESC_DATA0_DTYPE_MASK_ (0xC0000000)
+#define TX_DESC_DATA0_DTYPE_DATA_ (0x00000000)
+#define TX_DESC_DATA0_DTYPE_EXT_ (0x40000000)
+#define TX_DESC_DATA0_FS_ (0x20000000)
+#define TX_DESC_DATA0_LS_ (0x10000000)
+#define TX_DESC_DATA0_EXT_ (0x08000000)
+#define TX_DESC_DATA0_IOC_ (0x04000000)
+#define TX_DESC_DATA0_DTI_ (0x02000000)
+#define TX_DESC_DATA0_TSI_ (0x01000000)
+#define TX_DESC_DATA0_IGE_ (0x00800000)
+#define TX_DESC_DATA0_ICE_ (0x00400000)
+#define TX_DESC_DATA0_IPE_ (0x00200000)
+#define TX_DESC_DATA0_TPE_ (0x00100000)
+#define TX_DESC_DATA0_IVTG_ (0x00080000)
+#define TX_DESC_DATA0_RVTG_ (0x00040000)
+#define TX_DESC_DATA0_FCS_ (0x00020000)
+#define TX_DESC_DATA0_TSE_ (0x00010000)
+#define TX_DESC_DATA0_BUF_LENGTH_MASK_ (0x0000FFFF)
+
+#define TX_DESC_DATA0_EXT_LSO_ (0x00200000)
+#define TX_DESC_DATA0_EXT_PAY_LENGTH_MASK_ (0x000FFFFF)
+
+#define TX_DESC_DATA1_TADDRL_MASK_ (0xFFFFFFFF)
+#define TX_DESC_DATA2_TADDRH_MASK_ (0xFFFFFFFF)
+
+#define TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_ (0x3FFF0000)
+#define TX_DESC_DATA3_VTAG_MASK_ (0x0000FFFF)
+
+struct lan743x_tx_descriptor {
+ u32 data0;
+ u32 data1;
+ u32 data2;
+ u32 data3;
+} __aligned(DEFAULT_DMA_DESCRIPTOR_SPACING);
+
+#define TX_BUFFER_INFO_FLAG_ACTIVE BIT(0)
+#define TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED BIT(1)
+#define TX_BUFFER_INFO_FLAG_SKB_FRAGMENT BIT(2)
+struct lan743x_tx_buffer_info {
+ int flags;
+ struct sk_buff *skb;
+ dma_addr_t dma_ptr;
+ unsigned int buffer_length;
+};
+
+#define LAN743X_TX_RING_SIZE (50)
+
+static void lan743x_tx_isr(void *context, u32 int_sts)
+{
+ int enable_flag = 1;
+ struct lan743x_tx *tx = (struct lan743x_tx *)context;
+ struct lan743x_adapter *adapter = tx->adapter;
+
+ lan743x_csr_write(adapter, INT_EN_CLR,
+ INT_BIT_DMA_TX_(tx->channel_number));
+
+ if (int_sts & INT_BIT_DMA_TX_(tx->channel_number)) {
+ u32 dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS);
+ u32 dmac_int_en = lan743x_csr_read(adapter, DMAC_INT_EN_SET);
+ u32 ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number);
+ u32 stop_bit = DMAC_INT_BIT_TX_STOP_(tx->channel_number);
+
+ dmac_int_en &= (ioc_bit | stop_bit);
+ dmac_int_sts &= dmac_int_en;
+
+ if (dmac_int_sts & ioc_bit) {
+ tasklet_schedule(&tx->tx_isr_bottom_half);
+ enable_flag = 0;/* tasklet will re-enable later */
+ }
+ if (dmac_int_sts & stop_bit) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "unhandled tx stop interrupt");
+ /* clear dmac int sts */
+ lan743x_csr_write(adapter, DMAC_INT_STS, stop_bit);
+ }
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "unexpected interrupt, INT_BIT_DMA_TX_(%d) == 0",
+ tx->channel_number);
+ }
+ if (enable_flag)
+ /* enable isr */
+ lan743x_csr_write(adapter, INT_EN_SET,
+ INT_BIT_DMA_TX_(tx->channel_number));
+}
+
+static void lan743x_tx_release_desc(struct lan743x_tx *tx,
+ int descriptor_index, bool cleanup)
+{
+ struct lan743x_adapter *adapter = tx->adapter;
+ struct lan743x_tx_descriptor *descriptor = NULL;
+ struct lan743x_tx_buffer_info *buffer_info = NULL;
+ u32 descriptor_type = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (descriptor_index >= 0) &&
+ (descriptor_index < tx->ring_size));
+
+ descriptor = &tx->ring_cpu_ptr[descriptor_index];
+ buffer_info = &tx->buffer_info[descriptor_index];
+ if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_ACTIVE)) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !buffer_info->skb);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !buffer_info->dma_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !buffer_info->buffer_length);
+ goto done;
+ }
+
+ descriptor_type = (descriptor->data0) &
+ TX_DESC_DATA0_DTYPE_MASK_;
+ if (descriptor_type == TX_DESC_DATA0_DTYPE_DATA_) {
+ goto clean_up_data_descriptor;
+ } else if (descriptor_type == TX_DESC_DATA0_DTYPE_EXT_) {
+ /* ignore extension type */
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !buffer_info->skb);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !buffer_info->dma_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !buffer_info->buffer_length);
+ goto clear_active;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Unexpected descriptor type");
+ goto clear_active;
+ }
+clean_up_data_descriptor:
+ if (buffer_info->dma_ptr) {
+ if (buffer_info->flags &
+ TX_BUFFER_INFO_FLAG_SKB_FRAGMENT) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !(descriptor->data0 &
+ TX_DESC_DATA0_FS_));
+ dma_unmap_page(&tx->adapter->pci.pdev->dev,
+ buffer_info->dma_ptr,
+ buffer_info->buffer_length,
+ DMA_TO_DEVICE);
+ } else {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (descriptor->data0 &
+ TX_DESC_DATA0_FS_));
+ dma_unmap_single(&tx->adapter->pci.pdev->dev,
+ buffer_info->dma_ptr,
+ buffer_info->buffer_length,
+ DMA_TO_DEVICE);
+ }
+ buffer_info->dma_ptr = 0;
+ buffer_info->buffer_length = 0;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "buffer_info->phys_ptr == NULL at %d",
+ descriptor_index);
+ }
+ if (buffer_info->skb) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (descriptor->data0 &
+ TX_DESC_DATA0_LS_));
+ if (buffer_info->flags &
+ TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED) {
+ if (cleanup) {
+ lan743x_ptp_unrequest_tx_timestamp(tx->adapter);
+ dev_kfree_skb(buffer_info->skb);
+ } else {
+ lan743x_ptp_tx_timestamp_skb(tx->adapter,
+ buffer_info->skb);
+ }
+ } else {
+ dev_kfree_skb(buffer_info->skb);
+ }
+ buffer_info->skb = NULL;
+ }
+clear_active:
+ buffer_info->flags &= ~TX_BUFFER_INFO_FLAG_ACTIVE;
+done:
+ memset(buffer_info, 0, sizeof(*buffer_info));
+ memset(descriptor, 0, sizeof(*descriptor));
+}
+
+static inline int lan743x_tx_next_index(struct lan743x_tx *tx, int index)
+{
+ return ((++index) % tx->ring_size);
+}
+
+static void lan743x_tx_release_completed_descriptors(struct lan743x_tx *tx)
+{
+ while ((*tx->head_cpu_ptr) != (tx->last_head)) {
+ lan743x_tx_release_desc(tx, tx->last_head, false);
+
+ tx->last_head = lan743x_tx_next_index(tx, tx->last_head);
+ }
+}
+
+static void lan743x_tx_release_all_descriptors(struct lan743x_tx *tx)
+{
+ u32 original_head = 0;
+
+ original_head = tx->last_head;
+
+ do {
+ lan743x_tx_release_desc(tx, tx->last_head, true);
+ tx->last_head = lan743x_tx_next_index(tx, tx->last_head);
+ } while (tx->last_head != original_head);
+
+ memset(tx->ring_cpu_ptr, 0,
+ sizeof(*tx->ring_cpu_ptr) * (tx->ring_size));
+ memset(tx->buffer_info, 0,
+ sizeof(*tx->buffer_info) * (tx->ring_size));
+}
+
+static int lan743x_tx_get_desc_cnt(struct lan743x_tx *tx,
+ struct sk_buff *skb)
+{
+ struct lan743x_adapter *adapter = tx->adapter;
+ int result = 1;/* 1 for the main skb buffer */
+ int nr_frags = 0;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, skb);
+ if (skb_is_gso(skb))
+ result++;/* requires an extension descriptor */
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ NETIF_ASSERT(adapter, drv, adapter->netdev, nr_frags >= 0);
+ result += nr_frags; /* 1 for each fragment buffer */
+ return result;
+}
+
+static int lan743x_tx_get_avail_desc(struct lan743x_tx *tx)
+{
+ struct lan743x_adapter *adapter = tx->adapter;
+ int last_head = tx->last_head;
+ int last_tail = tx->last_tail;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (last_tail >= 0) && (last_tail < tx->ring_size));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ (last_head >= 0) && (last_head < tx->ring_size));
+ if (last_tail >= last_head)
+ return tx->ring_size - last_tail + last_head - 1;
+ else
+ return last_head - last_tail - 1;
+}
+
+static void lan743x_tx_isr_bottom_half(unsigned long param)
+{
+ unsigned long irq_flags = 0;
+ struct lan743x_tx *tx = NULL;
+ struct lan743x_adapter *adapter = NULL;
+ bool start_transmitter = false;
+ u32 ioc_bit = 0;
+
+ tx = (struct lan743x_tx *)param;
+ adapter = tx->adapter;
+ NETIF_ASSERT(adapter, drv, adapter->netdev, tx->ring_cpu_ptr);
+ ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number);
+
+ spin_lock_irqsave(&tx->ring_lock, irq_flags);
+ do {
+ /* clear dmac int sts */
+ lan743x_csr_write(adapter, DMAC_INT_STS, ioc_bit);
+ lan743x_csr_read(adapter, DMAC_INT_STS);
+
+ /* clean up tx ring */
+ lan743x_tx_release_completed_descriptors(tx);
+ } while (lan743x_csr_read(adapter, DMAC_INT_STS) & ioc_bit);
+
+ if (netif_queue_stopped(tx->adapter->netdev)) {
+ if (tx->overflow_skb) {
+ if (lan743x_tx_get_desc_cnt(tx, tx->overflow_skb) <=
+ lan743x_tx_get_avail_desc(
+ tx))
+ start_transmitter = true;
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "Why was queue stopped, with out any overflow skb?");
+ netif_wake_queue(tx->adapter->netdev);
+ }
+ } else if (tx->overflow_skb) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "why is queue not stopped when overflow skb is used");
+ }
+ spin_unlock_irqrestore(&tx->ring_lock, irq_flags);
+
+ if (start_transmitter) {
+ /* space is now available, transmit overflow skb */
+ lan743x_tx_xmit_frame(tx, tx->overflow_skb);
+ tx->overflow_skb = NULL;
+ netif_wake_queue(adapter->netdev);
+ }
+
+ /* enable isr */
+ lan743x_csr_write(adapter, INT_EN_SET,
+ INT_BIT_DMA_TX_(tx->channel_number));
+ lan743x_csr_read(adapter, INT_STS);
+}
+
+static int lan743x_tx_ring_init(struct lan743x_tx *tx)
+{
+ int ret = -ENOMEM;
+ int descriptor_spacing = 0;
+ size_t ring_allocation_size = 0;
+ dma_addr_t dma_ptr;
+ void *cpu_ptr = NULL;
+ struct lan743x_adapter *adapter = tx->adapter;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, tx->adapter);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !tx->ring_size);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !tx->ring_allocation_size);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !tx->ring_cpu_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !tx->ring_dma_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !tx->buffer_info);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !tx->head_cpu_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !tx->head_dma_ptr);
+
+ descriptor_spacing = lan743x_dmac_get_descriptor_spacing(tx->adapter);
+ if (sizeof(struct lan743x_tx_descriptor) != descriptor_spacing) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "sizeof(struct lan743x_tx_descriptor) != descriptor_spacing");
+ ret = -EPERM;
+ goto cleanup;
+ }
+
+ tx->ring_size = LAN743X_TX_RING_SIZE;
+
+ if ((tx->ring_size) & (~TX_CFG_B_TX_RING_LEN_MASK_)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "ring size is too large, tx_channel = %d",
+ tx->channel_number);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ring_allocation_size = ALIGN(tx->ring_size * descriptor_spacing,
+ PAGE_SIZE);
+
+ dma_ptr = 0;
+ cpu_ptr = pci_zalloc_consistent(tx->adapter->pci.pdev,
+ ring_allocation_size, &dma_ptr);
+ if (!cpu_ptr) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to allocate tx ring, channel = %d",
+ tx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ NETIF_ASSERT(adapter, drv, adapter->netdev, dma_ptr);
+ tx->ring_allocation_size = ring_allocation_size;
+ tx->ring_cpu_ptr = (struct lan743x_tx_descriptor *)cpu_ptr;
+ tx->ring_dma_ptr = dma_ptr;
+ if ((tx->ring_dma_ptr) & 0x3) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "dma ring base is not DWORD aligned, channel = %d",
+ tx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ cpu_ptr = kzalloc(tx->ring_size * sizeof(*tx->buffer_info), GFP_KERNEL);
+ if (!cpu_ptr) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to allocate buffer info, channel = %d",
+ tx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ tx->buffer_info = (struct lan743x_tx_buffer_info *)cpu_ptr;
+
+ dma_ptr = 0;
+ cpu_ptr = pci_zalloc_consistent(tx->adapter->pci.pdev,
+ sizeof(*tx->head_cpu_ptr), &dma_ptr);
+ if (!cpu_ptr) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to allocate head pointer, channel = %d",
+ tx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ NETIF_ASSERT(adapter, drv, adapter->netdev, dma_ptr);
+ tx->head_cpu_ptr = cpu_ptr;
+ tx->head_dma_ptr = dma_ptr;
+ if ((tx->head_dma_ptr) & 0x3) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "head write back pointer is not DWORD aligned, channel = %d",
+ tx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ret = 0;
+cleanup:
+ if (ret)
+ lan743x_tx_ring_cleanup(tx);
+ return ret;
+}
+
+static void lan743x_tx_ring_cleanup(struct lan743x_tx *tx)
+{
+ if (tx->head_cpu_ptr) {
+ pci_free_consistent(tx->adapter->pci.pdev,
+ sizeof(*tx->head_cpu_ptr),
+ (void *)(tx->head_cpu_ptr),
+ tx->head_dma_ptr);
+ tx->head_cpu_ptr = NULL;
+ tx->head_dma_ptr = 0;
+ }
+
+ kfree(tx->buffer_info);
+ tx->buffer_info = NULL;
+
+ if (tx->ring_cpu_ptr) {
+ pci_free_consistent(tx->adapter->pci.pdev,
+ tx->ring_allocation_size,
+ tx->ring_cpu_ptr,
+ tx->ring_dma_ptr);
+ tx->ring_allocation_size = 0;
+ tx->ring_cpu_ptr = NULL;
+ tx->ring_dma_ptr = 0;
+ }
+
+ tx->ring_size = 0;
+}
+
+static int lan743x_tx_init(struct lan743x_tx *tx,
+ struct lan743x_adapter *adapter, int tx_channel)
+{
+ int ret = -ENODEV;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, tx);
+ NETIF_ASSERT(adapter, probe, adapter->netdev, adapter);
+ memset(tx, 0, sizeof(*tx));
+ NETIF_ASSERT(adapter, probe, adapter->netdev, (tx_channel >= 0) &&
+ (tx_channel < LAN743X_NUMBER_OF_TX_CHANNELS));
+
+ tx->adapter = adapter;
+ tx->channel_number = -1;
+
+ ret = lan743x_dmac_reserve_tx_channel(adapter, tx_channel);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "Failed to reserve tx channel %d", tx_channel);
+ goto cleanup;
+ }
+ tx->channel_number = tx_channel;
+
+ spin_lock_init(&tx->ring_lock);
+
+ tasklet_init(&tx->tx_isr_bottom_half,
+ lan743x_tx_isr_bottom_half, (unsigned long)tx);
+ tasklet_disable(&tx->tx_isr_bottom_half);
+
+ ret = 0;
+
+cleanup:
+ if (ret)
+ lan743x_tx_cleanup(tx);
+ return ret;
+}
+
+static void lan743x_tx_cleanup(struct lan743x_tx *tx)
+{
+ struct lan743x_adapter *adapter = tx->adapter;
+
+ if (tx->channel_number >= 0) {
+ lan743x_dmac_release_tx_channel(adapter, tx->channel_number);
+ tx->channel_number = -1;
+ }
+
+ memset(tx, 0, sizeof(*tx));
+}
+
+static int lan743x_tx_open(struct lan743x_tx *tx)
+{
+ int ret = -ENODEV;
+ struct lan743x_adapter *adapter = NULL;
+ u32 data = 0;
+
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ (tx->channel_number >= 0) &&
+ (tx->channel_number < LAN743X_NUMBER_OF_TX_CHANNELS));
+ adapter = tx->adapter;
+
+ ret = lan743x_tx_ring_init(tx);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Tx Channel = %d, failed to initialize dma ring",
+ tx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ tx->flags |= TX_FLAG_RING_ALLOCATED;
+
+ /* enable mac */
+ ret = lan743x_mac_tx_enable(adapter, tx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "failed to enable mac, tx_channel = %d",
+ tx->channel_number);
+ goto cleanup;
+ }
+ tx->flags |= TX_FLAG_MAC_ENABLED;
+
+ /* initialize fifo */
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ !(tx->flags & TX_FLAG_FIFO_ENABLED));
+ ret = lan743x_fct_tx_reset(adapter, tx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Failed to reset tx fifo, tx_channel = %d",
+ tx->channel_number);
+ goto cleanup;
+ }
+
+ /* enable fifo */
+ ret = lan743x_fct_tx_enable(adapter, tx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Failed to enable tx fifo, tx_channel = %d",
+ tx->channel_number);
+ goto cleanup;
+ }
+ tx->flags |= TX_FLAG_FIFO_ENABLED;
+
+ /* reset tx channel */
+ ret = lan743x_dmac_tx_reset(adapter, tx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Failed to reset tx dmac, tx_channel = %d",
+ tx->channel_number);
+ goto cleanup;
+ }
+
+ /* Write TX_BASE_ADDR */
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ !((tx->ring_dma_ptr) & 0x3));
+ lan743x_csr_write(adapter,
+ TX_BASE_ADDRH(tx->channel_number),
+ DMA_ADDR_HIGH32(tx->ring_dma_ptr));
+ lan743x_csr_write(adapter,
+ TX_BASE_ADDRL(tx->channel_number),
+ DMA_ADDR_LOW32(tx->ring_dma_ptr));
+
+ /* Write TX_CFG_B */
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ !((tx->ring_size) & (~TX_CFG_B_TX_RING_LEN_MASK_)));
+ data = lan743x_csr_read(adapter, TX_CFG_B(tx->channel_number));
+ data &= ~TX_CFG_B_TX_RING_LEN_MASK_;
+ data |= ((tx->ring_size) & TX_CFG_B_TX_RING_LEN_MASK_);
+ lan743x_csr_write(adapter, TX_CFG_B(tx->channel_number), data);
+
+ /* Write TX_CFG_A */
+ data = TX_CFG_A_TX_TMR_HPWB_SEL_IOC_ | TX_CFG_A_TX_HP_WB_EN_;
+ lan743x_csr_write(adapter, TX_CFG_A(tx->channel_number), data);
+
+ /* Write TX_HEAD_WRITEBACK_ADDR */
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ !((tx->head_dma_ptr) & 0x3));
+ lan743x_csr_write(adapter,
+ TX_HEAD_WRITEBACK_ADDRH(tx->channel_number),
+ DMA_ADDR_HIGH32(tx->head_dma_ptr));
+ lan743x_csr_write(adapter,
+ TX_HEAD_WRITEBACK_ADDRL(tx->channel_number),
+ DMA_ADDR_LOW32(tx->head_dma_ptr));
+
+ /* set last head */
+ tx->last_head = lan743x_csr_read(adapter, TX_HEAD(tx->channel_number));
+ NETIF_ASSERT(adapter, ifup, adapter->netdev, !tx->last_head);
+
+ /* write TX_TAIL */
+ tx->last_tail = 0;
+ lan743x_csr_write(adapter, TX_TAIL(tx->channel_number),
+ (u32)(tx->last_tail));
+
+ tasklet_enable(&tx->tx_isr_bottom_half);
+ lan743x_csr_write(adapter, INT_EN_SET,
+ INT_BIT_DMA_TX_(tx->channel_number));
+ lan743x_csr_write(adapter, DMAC_INT_EN_SET,
+ DMAC_INT_BIT_TX_IOC_(tx->channel_number));
+ tx->flags |= TX_FLAG_ISR_ENABLED;
+
+ /* start dmac channel */
+ ret = lan743x_dmac_tx_start(adapter, tx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Failed to start tx channel %d",
+ tx->channel_number);
+ goto cleanup;
+ }
+ tx->flags |= TX_FLAG_DMAC_STARTED;
+
+ ret = 0;
+
+cleanup:
+ if (ret)
+ lan743x_tx_close(tx);
+ return ret;
+}
+
+static void lan743x_tx_close(struct lan743x_tx *tx)
+{
+ struct lan743x_adapter *adapter = tx->adapter;
+
+ if (tx->flags & TX_FLAG_DMAC_STARTED) {
+ lan743x_dmac_tx_stop(adapter, tx->channel_number);
+ tx->flags &= ~TX_FLAG_DMAC_STARTED;
+ }
+ if (tx->flags & TX_FLAG_ISR_ENABLED) {
+ lan743x_csr_write(adapter,
+ DMAC_INT_EN_CLR,
+ DMAC_INT_BIT_TX_IOC_(tx->channel_number));
+ lan743x_csr_write(adapter, INT_EN_CLR,
+ INT_BIT_DMA_TX_(tx->channel_number));
+ tasklet_disable(&tx->tx_isr_bottom_half);
+ tx->flags &= ~TX_FLAG_ISR_ENABLED;
+ }
+
+ if (tx->flags & TX_FLAG_FIFO_ENABLED) {
+ lan743x_fct_tx_disable(adapter, tx->channel_number);
+ tx->flags &= ~TX_FLAG_FIFO_ENABLED;
+ }
+
+ if (tx->flags & TX_FLAG_MAC_ENABLED) {
+ lan743x_mac_tx_disable(adapter, tx->channel_number);
+ tx->flags &= ~TX_FLAG_MAC_ENABLED;
+ }
+
+ lan743x_tx_release_all_descriptors(tx);
+
+ if (tx->overflow_skb) {
+ dev_kfree_skb(tx->overflow_skb);
+ tx->overflow_skb = NULL;
+ }
+
+ if (tx->flags & TX_FLAG_RING_ALLOCATED) {
+ lan743x_tx_ring_cleanup(tx);
+ tx->flags &= ~TX_FLAG_RING_ALLOCATED;
+ }
+}
+
+static void lan743x_tx_set_timestamping_enable(struct lan743x_tx *tx,
+ bool enabled)
+{
+ if (enabled)
+ tx->flags |= TX_FLAG_TIMESTAMPING_ENABLED;
+ else
+ tx->flags &= ~TX_FLAG_TIMESTAMPING_ENABLED;
+}
+
+static int lan743x_tx_frame_start(struct lan743x_tx *tx,
+ unsigned char *first_buffer,
+ unsigned int first_buffer_length,
+ unsigned int frame_length,
+ bool time_stamp,
+ bool check_sum)
+{
+ /* called only from within lan743x_tx_xmit_frame.
+ * assuming tx->ring_lock has already been acquired.
+ */
+ struct lan743x_adapter *adapter = tx->adapter;
+ struct lan743x_tx_descriptor *tx_descriptor = NULL;
+ struct lan743x_tx_buffer_info *buffer_info = NULL;
+ struct device *dev = &adapter->pci.pdev->dev;
+ dma_addr_t dma_ptr;
+
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev, first_buffer);
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ !(tx->frame_flags & TX_FRAME_FLAG_IN_PROGRESS));
+
+ tx->frame_flags |= TX_FRAME_FLAG_IN_PROGRESS;
+
+ tx->frame_first = lan743x_csr_read(adapter,
+ TX_TAIL(tx->channel_number));
+ tx->frame_tail = tx->frame_first;
+
+ if (tx->frame_tail != tx->last_tail) {
+ NETIF_ERROR(adapter, tx_queued, adapter->netdev,
+ "unexpected tail index, tail=%d, last_tail=%d",
+ tx->frame_tail, tx->last_tail);
+ return -EPERM;
+ }
+
+ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
+ buffer_info = &tx->buffer_info[tx->frame_tail];
+
+ dma_ptr = dma_map_single(dev, first_buffer, first_buffer_length,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, dma_ptr)) {
+ NETIF_ERROR(adapter, tx_queued, adapter->netdev,
+ "DMA mapping error");
+ return -ENOMEM;
+ }
+
+ tx_descriptor->data1 = DMA_ADDR_LOW32(dma_ptr);
+ tx_descriptor->data2 = DMA_ADDR_HIGH32(dma_ptr);
+ tx_descriptor->data3 = (frame_length << 16) &
+ TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_;
+
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ !((buffer_info->flags) & TX_BUFFER_INFO_FLAG_ACTIVE));
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev, !buffer_info->skb);
+
+ buffer_info->skb = NULL;
+ buffer_info->dma_ptr = dma_ptr;
+ buffer_info->buffer_length = first_buffer_length;
+ buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
+
+ tx->frame_data0 = (first_buffer_length &
+ TX_DESC_DATA0_BUF_LENGTH_MASK_) |
+ TX_DESC_DATA0_DTYPE_DATA_ |
+ TX_DESC_DATA0_FS_ |
+ TX_DESC_DATA0_FCS_;
+
+ if (time_stamp)
+ tx->frame_data0 |= TX_DESC_DATA0_TSE_;
+ if (check_sum)
+ tx->frame_data0 |= TX_DESC_DATA0_ICE_ |
+ TX_DESC_DATA0_IPE_ |
+ TX_DESC_DATA0_TPE_;
+
+ /* data0 will be programmed in one of other frame assembler functions */
+
+ return 0;
+}
+
+static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx,
+ unsigned int frame_length)
+{
+ /* called only from within lan743x_tx_xmit_frame.
+ * assuming tx->ring_lock has already been acquired.
+ */
+ struct lan743x_adapter *adapter = tx->adapter;
+ struct lan743x_tx_descriptor *tx_descriptor = NULL;
+ struct lan743x_tx_buffer_info *buffer_info = NULL;
+
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ (tx->frame_flags & TX_FRAME_FLAG_IN_PROGRESS));
+
+ /* wrap up previous descriptor */
+ tx->frame_data0 |= TX_DESC_DATA0_EXT_;
+ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
+ tx_descriptor->data0 = tx->frame_data0;
+
+ /* move to next descriptor */
+ tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
+ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
+ buffer_info = &tx->buffer_info[tx->frame_tail];
+
+ /* add extension descriptor */
+ tx_descriptor->data1 = 0;
+ tx_descriptor->data2 = 0;
+ tx_descriptor->data3 = 0;
+
+ buffer_info->skb = NULL;
+ buffer_info->dma_ptr = 0;
+ buffer_info->buffer_length = 0;
+ buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
+
+ tx->frame_data0 = (frame_length & TX_DESC_DATA0_EXT_PAY_LENGTH_MASK_) |
+ TX_DESC_DATA0_DTYPE_EXT_ |
+ TX_DESC_DATA0_EXT_LSO_;
+
+ /* data0 will be programmed in one of other frame assembler functions */
+}
+
+static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx,
+ const struct skb_frag_struct *fragment,
+ unsigned int frame_length)
+{
+ /* called only from within lan743x_tx_xmit_frame
+ * assuming tx->ring_lock has already been acquired
+ */
+ struct lan743x_adapter *adapter = tx->adapter;
+ struct lan743x_tx_descriptor *tx_descriptor = NULL;
+ struct lan743x_tx_buffer_info *buffer_info = NULL;
+ unsigned int fragment_length = 0;
+ struct device *dev = &adapter->pci.pdev->dev;
+ dma_addr_t dma_ptr;
+
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ (tx->frame_flags & TX_FRAME_FLAG_IN_PROGRESS));
+
+ fragment_length = skb_frag_size(fragment);
+ if (!fragment_length)
+ return 0;
+
+ /* wrap up previous descriptor */
+ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
+ tx_descriptor->data0 = tx->frame_data0;
+
+ /* move to next descriptor */
+ tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
+ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
+ buffer_info = &tx->buffer_info[tx->frame_tail];
+
+ dma_ptr = skb_frag_dma_map(dev, fragment,
+ 0, fragment_length,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, dma_ptr)) {
+ int desc_index;
+
+ NETIF_ERROR(adapter, tx_queued, adapter->netdev,
+ "fragment, DMA mapping error");
+
+ /* cleanup all previously setup descriptors */
+ desc_index = tx->frame_first;
+ while (desc_index != tx->frame_tail) {
+ lan743x_tx_release_desc(tx, desc_index, true);
+ desc_index = lan743x_tx_next_index(tx,
+ desc_index);
+ }
+ dma_wmb();
+
+ tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS;
+ tx->frame_first = 0;
+ tx->frame_data0 = 0;
+ tx->frame_tail = 0;
+ return -ENOMEM;
+ }
+ tx_descriptor->data1 = DMA_ADDR_LOW32(dma_ptr);
+ tx_descriptor->data2 = DMA_ADDR_HIGH32(dma_ptr);
+ tx_descriptor->data3 = (frame_length << 16) &
+ TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_;
+ buffer_info->skb = NULL;
+ buffer_info->dma_ptr = dma_ptr;
+ buffer_info->buffer_length = fragment_length;
+ buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
+ buffer_info->flags |= TX_BUFFER_INFO_FLAG_SKB_FRAGMENT;
+
+ tx->frame_data0 = (fragment_length & TX_DESC_DATA0_BUF_LENGTH_MASK_) |
+ TX_DESC_DATA0_DTYPE_DATA_ |
+ TX_DESC_DATA0_FCS_;
+
+ /* data0 will be programmed in one of other frame assembler functions */
+ return 0;
+}
+
+static void lan743x_tx_frame_end(struct lan743x_tx *tx,
+ struct sk_buff *skb,
+ bool time_stamp)
+{
+ /* called only from within lan743x_tx_xmit_frame
+ * assuming tx->ring_lock has already been acquired
+ */
+ struct lan743x_adapter *adapter = tx->adapter;
+ struct lan743x_tx_descriptor *tx_descriptor = NULL;
+ struct lan743x_tx_buffer_info *buffer_info = NULL;
+
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ (tx->frame_flags & TX_FRAME_FLAG_IN_PROGRESS));
+
+ /* wrap up previous descriptor */
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ !(tx->frame_data0 & TX_DESC_DATA0_DTYPE_EXT_));
+ tx->frame_data0 |= TX_DESC_DATA0_LS_;
+ tx->frame_data0 |= TX_DESC_DATA0_IOC_;
+
+ tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
+ buffer_info = &tx->buffer_info[tx->frame_tail];
+ buffer_info->skb = skb;
+ if (time_stamp)
+ buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED;
+ tx_descriptor->data0 = tx->frame_data0;
+
+ tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
+ tx->last_tail = tx->frame_tail;
+
+ dma_wmb();
+
+ lan743x_csr_write(adapter, TX_TAIL(tx->channel_number), tx->frame_tail);
+
+ tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS;
+}
+
+static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
+ struct sk_buff *skb)
+{
+ unsigned long irq_flags = 0;
+ int required_number_of_descriptors = 0;
+ struct lan743x_adapter *adapter = tx->adapter;
+ unsigned int frame_length = 0;
+ unsigned int head_length = 0;
+ unsigned int start_frame_length = 0;
+ int nr_frags = 0;
+ bool do_timestamp = false;
+ bool gso = false;
+ int j;
+
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev, skb);
+
+ if (skb->len > 0xFFFF) {
+ NETIF_WARNING(adapter, tx_queued, adapter->netdev,
+ "dropping packet, length too large, skb->len = %d",
+ skb->len);
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ spin_lock_irqsave(&tx->ring_lock, irq_flags);
+
+ required_number_of_descriptors = lan743x_tx_get_desc_cnt(tx, skb);
+ if (required_number_of_descriptors >
+ lan743x_tx_get_avail_desc(tx)) {
+ if (required_number_of_descriptors > (tx->ring_size - 1)) {
+ NETIF_WARNING(adapter, tx_queued, adapter->netdev,
+ "dropping packet, requires too many descriptors, %d",
+ required_number_of_descriptors);
+ dev_kfree_skb(skb);
+ } else {
+ /* save to overflow buffer */
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ !tx->overflow_skb);
+ tx->overflow_skb = skb;
+ netif_stop_queue(tx->adapter->netdev);
+ }
+ goto unlock;
+ }
+
+ /* space available, transmit skb */
+
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
+ if (tx->flags & TX_FLAG_TIMESTAMPING_ENABLED) {
+ if (lan743x_ptp_request_tx_timestamp(adapter)) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ do_timestamp = true;
+ } else {
+ NETIF_WARNING(adapter, tx_queued,
+ adapter->netdev,
+ "Timestamp request denied, too many requests in progress");
+ }
+ } else {
+ NETIF_WARNING(adapter, tx_queued, adapter->netdev,
+ "Tx Timestamp requested but tx timestamping is not enabled");
+ }
+ }
+
+ head_length = skb_headlen(skb);
+ frame_length = skb_pagelen(skb);
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ if (!nr_frags) {
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ head_length == frame_length);
+ }
+ start_frame_length = frame_length;
+ gso = skb_is_gso(skb);
+ if (gso) {
+ if (nr_frags <= 0) {
+ NETIF_ERROR(adapter, tx_queued, adapter->netdev,
+ "Large segment requested, but no fragments");
+ dev_kfree_skb(skb);
+ goto unlock;
+ }
+ start_frame_length = max(skb_shinfo(skb)->gso_size,
+ (unsigned short)8);
+ }
+
+ if (lan743x_tx_frame_start(tx,
+ skb->data, head_length,
+ start_frame_length,
+ do_timestamp,
+ skb->ip_summed == CHECKSUM_PARTIAL)) {
+ NETIF_ERROR(adapter, tx_queued, adapter->netdev,
+ "frame start error");
+ dev_kfree_skb(skb);
+ goto unlock;
+ }
+
+ if (gso) {
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ nr_frags > 0);
+ lan743x_tx_frame_add_lso(tx, frame_length);
+ }
+
+ if (nr_frags <= 0) {
+ NETIF_ASSERT(adapter, tx_queued, adapter->netdev,
+ !nr_frags);
+ goto finish;
+ }
+
+ for (j = 0; j < nr_frags; j++) {
+ const struct skb_frag_struct *frag;
+
+ frag = &(skb_shinfo(skb)->frags[j]);
+ if (lan743x_tx_frame_add_fragment(tx, frag, frame_length)) {
+ /* upon error no need to call
+ * lan743x_tx_frame_end
+ * frame assembler clean up was performed inside
+ * lan743x_tx_frame_add_fragment
+ */
+ NETIF_ERROR(adapter, tx_queued, adapter->netdev,
+ "Error adding fragment to DMA ring");
+ dev_kfree_skb(skb);
+ goto unlock;
+ }
+ }
+
+finish:
+ lan743x_tx_frame_end(tx, skb, do_timestamp);
+unlock:
+ spin_unlock_irqrestore(&tx->ring_lock, irq_flags);
+ return NETDEV_TX_OK;
+}
+
+/* RX */
+
+/* OWN bit is set. ie, Descs are owned by RX DMAC */
+#define RX_DESC_DATA0_OWN_ (0x00008000)
+#define RX_DESC_DATA0_LENGTH_MASK_ (0x00003FFF)
+#define RX_DESC_DATA1_RADDRL_MASK_ (0xFFFFFFFF)
+#define RX_DESC_DATA2_RADDRH_MASK_ (0xFFFFFFFF)
+
+/* OWN bit is clear. ie, Descs are owned by host */
+#define RX_DESC_DATA0_FS_ (0x80000000)
+#define RX_DESC_DATA0_LS_ (0x40000000)
+#define RX_DESC_DATA0_FRAME_LENGTH_MASK_ (0x3FFF0000)
+#define RX_DESC_DATA0_FRAME_LENGTH_GET_(data0) \
+ (((data0) & RX_DESC_DATA0_FRAME_LENGTH_MASK_) >> 16)
+#define RX_DESC_DATA0_EXT_ (0x00004000)
+#define RX_DESC_DATA0_BUF_LENGTH_MASK_ (0x00003FFF)
+#define RX_DESC_DATA1_RSS_TYPE_MASK_ (0xF0000000)
+#define RX_DESC_DATA1_RX_STATUS_MASK_ (0x00FFFFFF)
+#define RX_DESC_DATA1_RX_STATUS_PRI_ (0x00800000)
+#define RX_DESC_DATA1_RX_STATUS_LEN_ERR_ (0x00400000)
+#define RX_DESC_DATA1_RX_STATUS_TS_ (0x00200000)
+#define RX_DESC_DATA1_RX_STATUS_1588_ (0x00100000)
+#define RX_DESC_DATA1_RX_STATUS_WAKE_ (0x00080000)
+#define RX_DESC_DATA1_RX_STATUS_RFE_FAIL_ (0x00040000)
+#define RX_DESC_DATA1_RX_STATUS_ICE_ (0x00020000)
+#define RX_DESC_DATA1_RX_STATUS_TCE_ (0x00010000)
+#define RX_DESC_DATA1_RX_STATUS_IPV_ (0x00008000)
+#define RX_DESC_DATA1_RX_STATUS_PID_MASK_ (0x00006000)
+#define RX_DESC_DATA1_RX_STATUS_PFF_ (0x00001000)
+#define RX_DESC_DATA1_RX_STATUS_BAM_ (0x00000800)
+#define RX_DESC_DATA1_RX_STATUS_MAM_ (0x00000400)
+#define RX_DESC_DATA1_RX_STATUS_FVTG_ (0x00000200)
+#define RX_DESC_DATA1_RX_STATUS_RED_ (0x00000100)
+#define RX_DESC_DATA1_RX_STATUS_RWT_ (0x00000080)
+#define RX_DESC_DATA1_RX_STATUS_RUNT_ (0x00000040)
+#define RX_DESC_DATA1_RX_STATUS_LONG_ (0x00000020)
+#define RX_DESC_DATA1_RX_STATUS_RXE_ (0x00000010)
+#define RX_DESC_DATA1_RX_STATUS_ALN_ (0x00000008)
+#define RX_DESC_DATA1_RX_STATUS_FCS_ (0x00000004)
+#define RX_DESC_DATA1_RX_STATUS_UAM_ (0x00000002)
+#define RX_DESC_DATA1_RX_STATUS_ICSM_ (0x00000001)
+
+#define RX_DESC_DATA2_CSUM_MASK_ (0xFFFF0000)
+#define RX_DESC_DATA2_VTAG_MASK_ (0x0000FFFF)
+#define RX_DESC_DATA2_TS_NS_MASK_ (0x3FFFFFFF)
+
+#define RX_DESC_DATA3_RSSHASH_MASK_ (0xFFFFFFFF)
+
+#if ((NET_IP_ALIGN != 0) && (NET_IP_ALIGN != 2))
+#error NET_IP_ALIGN must be 0 or 2
+#endif
+
+#define RX_HEAD_PADDING NET_IP_ALIGN
+
+struct lan743x_rx_descriptor {
+ u32 data0;
+ u32 data1;
+ u32 data2;
+ u32 data3;
+} __aligned(DEFAULT_DMA_DESCRIPTOR_SPACING);
+
+#define RX_BUFFER_INFO_FLAG_ACTIVE BIT(0)
+struct lan743x_rx_buffer_info {
+ int flags;
+ struct sk_buff *skb;
+
+ dma_addr_t dma_ptr;
+ unsigned int buffer_length;
+};
+
+#define LAN743X_RX_RING_SIZE (65)
+
+static inline int lan743x_rx_next_index(struct lan743x_rx *rx, int index)
+{
+ return ((++index) % rx->ring_size);
+}
+
+static int lan743x_rx_allocate_ring_element(struct lan743x_rx *rx,
+ int element_index)
+{
+ int ret = 0;
+ struct lan743x_rx_descriptor *descriptor;
+ struct lan743x_rx_buffer_info *buffer_info;
+ int length = 0;
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (element_index >= 0) &&
+ (element_index < rx->ring_size));
+ NETIF_ASSERT(adapter, drv, adapter->netdev, rx->ring_cpu_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, rx->buffer_info);
+ length = (LAN743X_MAX_FRAME_SIZE + ETH_HLEN + 4 + RX_HEAD_PADDING);
+ descriptor = &rx->ring_cpu_ptr[element_index];
+ buffer_info = &rx->buffer_info[element_index];
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !(descriptor->data0 & RX_DESC_DATA0_OWN_));
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !buffer_info->skb);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !buffer_info->dma_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !buffer_info->buffer_length);
+
+ buffer_info->skb = __netdev_alloc_skb(rx->adapter->netdev,
+ length,
+ GFP_ATOMIC | GFP_DMA);
+ if (!(buffer_info->skb)) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ buffer_info->dma_ptr = dma_map_single(&rx->adapter->pci.pdev->dev,
+ buffer_info->skb->data,
+ length,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&rx->adapter->pci.pdev->dev,
+ buffer_info->dma_ptr)) {
+ buffer_info->dma_ptr = 0;
+ ret = -ENOMEM;
+ goto done;
+ }
+ buffer_info->buffer_length = length;
+
+ descriptor->data1 = DMA_ADDR_LOW32(buffer_info->dma_ptr);
+ descriptor->data2 = DMA_ADDR_HIGH32(buffer_info->dma_ptr);
+ descriptor->data3 = 0;
+ descriptor->data0 = (RX_DESC_DATA0_OWN_ |
+ (length & RX_DESC_DATA0_BUF_LENGTH_MASK_));
+
+ skb_reserve(buffer_info->skb, RX_HEAD_PADDING);
+
+ ret = 0;
+done:
+ return ret;
+}
+
+static void lan743x_rx_reuse_ring_element(struct lan743x_rx *rx,
+ int element_index)
+{
+ struct lan743x_rx_descriptor *descriptor;
+ struct lan743x_rx_buffer_info *buffer_info;
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ descriptor = &rx->ring_cpu_ptr[element_index];
+ buffer_info = &rx->buffer_info[element_index];
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !(descriptor->data0 & RX_DESC_DATA0_OWN_));
+ NETIF_ASSERT(adapter, drv, adapter->netdev, buffer_info->skb);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, buffer_info->dma_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ buffer_info->buffer_length);
+
+ descriptor->data1 = DMA_ADDR_LOW32(buffer_info->dma_ptr);
+ descriptor->data2 = DMA_ADDR_HIGH32(buffer_info->dma_ptr);
+ descriptor->data3 = 0;
+ descriptor->data0 = (RX_DESC_DATA0_OWN_ |
+ ((buffer_info->buffer_length) &
+ RX_DESC_DATA0_BUF_LENGTH_MASK_));
+}
+
+static void lan743x_rx_release_ring_element(struct lan743x_rx *rx,
+ int element_index)
+{
+ struct lan743x_rx_descriptor *descriptor;
+ struct lan743x_rx_buffer_info *buffer_info;
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, (element_index >= 0) &&
+ (element_index < rx->ring_size));
+ descriptor = &rx->ring_cpu_ptr[element_index];
+ buffer_info = &rx->buffer_info[element_index];
+ memset(descriptor, 0, sizeof(*descriptor));
+ if (buffer_info->dma_ptr) {
+ dma_unmap_single(&rx->adapter->pci.pdev->dev,
+ buffer_info->dma_ptr,
+ buffer_info->buffer_length,
+ DMA_FROM_DEVICE);
+ buffer_info->dma_ptr = 0;
+ }
+ if (buffer_info->skb) {
+ dev_kfree_skb(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ memset(buffer_info, 0, sizeof(*buffer_info));
+}
+
+static void lan743x_rx_isr(void *context, u32 int_sts)
+{
+ int enable_flag = 1;
+ struct lan743x_rx *rx = (struct lan743x_rx *)context;
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ lan743x_csr_write(adapter, INT_EN_CLR,
+ INT_BIT_DMA_RX_(rx->channel_number));
+
+ if (int_sts & INT_BIT_DMA_RX_(rx->channel_number)) {
+ u32 dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS);
+ u32 dmac_int_en = lan743x_csr_read(adapter, DMAC_INT_EN_SET);
+ u32 rx_frame_bit = DMAC_INT_BIT_RXFRM_(rx->channel_number);
+ u32 stop_bit = DMAC_INT_BIT_RX_STOP_(rx->channel_number);
+
+ dmac_int_en &= (rx_frame_bit | stop_bit);
+ dmac_int_sts &= dmac_int_en;
+ if (dmac_int_sts & rx_frame_bit) {
+ napi_schedule(&rx->napi);
+ enable_flag = 0;/* poll function will re-enable later */
+ }
+ if (dmac_int_sts & stop_bit) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "unhandled rx stop interrupt");
+ /* clear dmac int sts */
+ lan743x_csr_write(adapter, DMAC_INT_STS, stop_bit);
+ }
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "unexpected interrupt, INT_BIT_DMA_RX_(%d) == 0",
+ rx->channel_number);
+ }
+ if (enable_flag) {
+ /* enable isr */
+ lan743x_csr_write(adapter, INT_EN_SET,
+ INT_BIT_DMA_RX_(rx->channel_number));
+ }
+}
+
+#define RX_PROCESS_RESULT_NOTHING_TO_DO (0)
+#define RX_PROCESS_RESULT_PACKET_RECEIVED (1)
+#define RX_PROCESS_RESULT_PACKET_DROPPED (2)
+static int lan743x_rx_process_packet(struct lan743x_rx *rx)
+{
+ int result = RX_PROCESS_RESULT_NOTHING_TO_DO;
+ int first_index = -1;
+ int last_index = -1;
+ int extension_index = -1;
+ int current_head_index = -1;
+ struct lan743x_rx_descriptor *descriptor;
+ struct lan743x_rx_buffer_info *buffer_info;
+ struct lan743x_adapter *adapter = rx->adapter;
+ struct skb_shared_hwtstamps *hwtstamps = NULL;
+
+ current_head_index = *rx->head_cpu_ptr;
+ if ((current_head_index < 0) || (current_head_index >= rx->ring_size)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "out of range, current_head_index = %d",
+ current_head_index);
+ goto done;
+ }
+ if ((rx->last_head < 0) || (rx->last_head >= rx->ring_size)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "out of range, last_head = %d",
+ rx->last_head);
+ goto done;
+ }
+ if (rx->last_head != current_head_index) {
+ descriptor = &rx->ring_cpu_ptr[rx->last_head];
+ if (descriptor->data0 & RX_DESC_DATA0_OWN_) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Head index updated, but descriptor still owned by DMAC (1)");
+ goto done;
+ }
+ if (!(descriptor->data0 & RX_DESC_DATA0_FS_)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "first segment missing");
+ goto done;
+ }
+
+ first_index = rx->last_head;
+ if (descriptor->data0 & RX_DESC_DATA0_LS_) {
+ last_index = rx->last_head;
+ } else {
+ int index;
+
+ if (descriptor->data0 & RX_DESC_DATA0_EXT_) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Extension bit set, not expected (1)");
+ }
+ index = lan743x_rx_next_index(rx, first_index);
+ while (index != current_head_index) {
+ descriptor = &rx->ring_cpu_ptr[index];
+ if (descriptor->data0 & RX_DESC_DATA0_OWN_) {
+ NETIF_ERROR(adapter, drv,
+ adapter->netdev,
+ "Head index updated, but descriptor still owned by DMAC (2)");
+ goto done;
+ }
+ if (descriptor->data0 & RX_DESC_DATA0_FS_) {
+ NETIF_ERROR(adapter, drv,
+ adapter->netdev,
+ "First Segment set, not expected");
+ }
+ if (descriptor->data0 & RX_DESC_DATA0_LS_) {
+ last_index = index;
+ break;
+ } else if (descriptor->data0 &
+ RX_DESC_DATA0_EXT_) {
+ NETIF_ERROR(adapter, drv,
+ adapter->netdev,
+ "Extension bit set, not expected (2)");
+ }
+ index = lan743x_rx_next_index(rx, index);
+ }
+ }
+ if (last_index >= 0) {
+ descriptor = &rx->ring_cpu_ptr[last_index];
+ if (descriptor->data0 & RX_DESC_DATA0_EXT_) {
+ /* extension is expected to follow */
+ int index = lan743x_rx_next_index(rx,
+ last_index);
+ if (index != current_head_index) {
+ descriptor = &rx->ring_cpu_ptr[index];
+ if (descriptor->data0 &
+ RX_DESC_DATA0_OWN_) {
+ NETIF_ERROR(adapter, drv,
+ adapter->netdev,
+ "Head index updated, but descriptor still owned by DMAC (3)");
+ goto done;
+ }
+ if (descriptor->data0 &
+ RX_DESC_DATA0_EXT_) {
+ extension_index = index;
+ } else {
+ NETIF_ERROR(adapter, drv,
+ adapter->netdev,
+ "Expected extension after last segment");
+ goto done;
+ }
+ } else {
+ /* extension is not yet available */
+ /* prevent processing of this packet */
+ first_index = -1;
+ last_index = -1;
+ }
+ }
+ }
+ }
+ if ((first_index >= 0) && (last_index >= 0)) {
+ struct sk_buff *skb = NULL;
+ u32 ts_sec = 0;
+ u32 ts_nsec = 0;
+ int real_last_index = last_index;
+ /* packet is available */
+ if (first_index == last_index) {
+ /* single buffer packet */
+ int packet_length;
+
+ buffer_info = &rx->buffer_info[first_index];
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ buffer_info->skb);
+ skb = buffer_info->skb;
+ descriptor = &rx->ring_cpu_ptr[first_index];
+
+ /* unmap from dma */
+ if (buffer_info->dma_ptr) {
+ dma_unmap_single(&rx->adapter->pci.pdev->dev,
+ buffer_info->dma_ptr,
+ buffer_info->buffer_length,
+ DMA_FROM_DEVICE);
+ buffer_info->dma_ptr = 0;
+ buffer_info->buffer_length = 0;
+ } else {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "No DMA ptr found");
+ }
+ buffer_info->skb = NULL;
+
+ packet_length = RX_DESC_DATA0_FRAME_LENGTH_GET_(
+ descriptor->data0);
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ sizeof(*skb->data) == 1);
+ skb_put(skb, packet_length - 4);
+ skb->protocol = eth_type_trans(skb,
+ rx->adapter->netdev);
+
+ lan743x_rx_allocate_ring_element(rx, first_index);
+ } else {
+ int index = first_index;
+ /* multi buffer packet */
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "multi buffer packet not supported");
+ /* this should not happen since
+ * buffers are allocated to be at least jumbo size
+ */
+
+ /* clean up buffers */
+ if (first_index <= last_index) {
+ while ((index >= first_index) &&
+ (index <= last_index)) {
+ lan743x_rx_release_ring_element(rx,
+ index);
+ lan743x_rx_allocate_ring_element(rx,
+ index);
+ index = lan743x_rx_next_index(rx,
+ index);
+ }
+ } else {
+ while ((index >= first_index) ||
+ (index <= last_index)) {
+ lan743x_rx_release_ring_element(rx,
+ index);
+ lan743x_rx_allocate_ring_element(rx,
+ index);
+ index = lan743x_rx_next_index(rx,
+ index);
+ }
+ }
+ }
+ if (extension_index >= 0) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ extension_index ==
+ lan743x_rx_next_index(rx, last_index));
+ descriptor = &rx->ring_cpu_ptr[extension_index];
+ buffer_info = &rx->buffer_info[extension_index];
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ !(descriptor->data0 &
+ (RX_DESC_DATA0_FS_ |
+ RX_DESC_DATA0_LS_ |
+ RX_DESC_DATA0_OWN_)));
+ NETIF_ASSERT(adapter, drv, adapter->netdev,
+ descriptor->data0 &
+ RX_DESC_DATA0_EXT_);
+ ts_sec = descriptor->data1;
+ ts_nsec = (descriptor->data2 &
+ RX_DESC_DATA2_TS_NS_MASK_);
+ lan743x_rx_reuse_ring_element(rx, extension_index);
+ real_last_index = extension_index;
+ }
+
+ if (!skb) {
+ result = RX_PROCESS_RESULT_PACKET_DROPPED;
+ goto move_forward;
+ }
+ if (extension_index < 0)
+ goto pass_packet_to_os;
+
+ hwtstamps = skb_hwtstamps(skb);
+ if (hwtstamps) {
+ hwtstamps->hwtstamp = ktime_set(ts_sec, ts_nsec);
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "hwtstamps == NULL");
+ }
+pass_packet_to_os:
+ /* pass packet to OS */
+ napi_gro_receive(&rx->napi, skb);
+ result = RX_PROCESS_RESULT_PACKET_RECEIVED;
+move_forward:
+ /* push tail and head forward */
+ lan743x_csr_write(adapter, RX_TAIL(rx->channel_number),
+ real_last_index);
+ rx->last_head = lan743x_rx_next_index(rx, real_last_index);
+ }
+done:
+ return result;
+}
+
+static int lan743x_rx_napi_poll(struct napi_struct *napi, int weight)
+{
+ int count;
+ bool finished = false;
+ struct lan743x_rx *rx = container_of(napi,
+ struct lan743x_rx, napi);
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ if (weight < 0)
+ finished = true;
+
+ count = 0;
+ while (count < weight) {
+ int rx_process_result = -1;
+
+ /* clear int status bit before reading packet */
+ lan743x_csr_write(adapter, DMAC_INT_STS,
+ DMAC_INT_BIT_RXFRM_(rx->channel_number));
+ lan743x_csr_read(adapter, DMAC_INT_STS);
+
+ rx_process_result = lan743x_rx_process_packet(rx);
+ if (rx_process_result == RX_PROCESS_RESULT_PACKET_RECEIVED) {
+ count++;
+ } else if (rx_process_result ==
+ RX_PROCESS_RESULT_NOTHING_TO_DO) {
+ finished = true;
+ break;
+ } else if (rx_process_result ==
+ RX_PROCESS_RESULT_PACKET_DROPPED) {
+ continue;
+ } else {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Unknown rx_process_result == %d",
+ rx_process_result);
+ }
+ }
+
+ adapter->netdev->stats.rx_packets += count;
+
+ if (!finished) {
+ NETIF_ASSERT(adapter, drv, adapter->netdev, count == weight);
+ return count;
+ }
+
+ napi_complete_done(napi, count);
+
+ lan743x_csr_write(adapter, INT_EN_SET,
+ INT_BIT_DMA_RX_(rx->channel_number));
+ lan743x_csr_read(adapter, INT_STS);
+
+ return 0;
+}
+
+static int lan743x_rx_ring_init(struct lan743x_rx *rx)
+{
+ int ret = -ENOMEM;
+ int descriptor_spacing = 0;
+ int element_index = 0;
+ size_t ring_allocation_size = 0;
+ dma_addr_t dma_ptr = 0;
+ void *cpu_ptr = NULL;
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, rx->adapter);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !rx->ring_size);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !rx->ring_allocation_size);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !rx->ring_cpu_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !rx->ring_dma_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !rx->buffer_info);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !rx->head_cpu_ptr);
+ NETIF_ASSERT(adapter, drv, adapter->netdev, !rx->head_dma_ptr);
+
+ descriptor_spacing = lan743x_dmac_get_descriptor_spacing(rx->adapter);
+ if (sizeof(struct lan743x_rx_descriptor) != descriptor_spacing) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "sizeof(struct lan743x_rx_descriptor) != descriptor_spacing");
+ ret = -EPERM;
+ goto cleanup;
+ }
+
+ rx->ring_size = LAN743X_RX_RING_SIZE;
+
+ if (rx->ring_size <= 1) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "rx_channel = %d, ring_size = %d",
+ rx->channel_number, rx->ring_size);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ if ((rx->ring_size) & (~RX_CFG_B_RX_RING_LEN_MASK_)) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "ring size is too large, rx_channel = %d",
+ rx->channel_number);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ring_allocation_size = ALIGN(rx->ring_size * descriptor_spacing,
+ PAGE_SIZE);
+
+ dma_ptr = 0;
+ cpu_ptr = pci_zalloc_consistent(rx->adapter->pci.pdev,
+ ring_allocation_size, &dma_ptr);
+ if (!cpu_ptr) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to allocate rx ring, channel = %d",
+ rx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ NETIF_ASSERT(adapter, drv, adapter->netdev, dma_ptr);
+ rx->ring_allocation_size = ring_allocation_size;
+ rx->ring_cpu_ptr = (struct lan743x_rx_descriptor *)cpu_ptr;
+ rx->ring_dma_ptr = dma_ptr;
+ if ((rx->ring_dma_ptr) & 0x3) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "dma ring base is not DWORD aligned, channel = %d",
+ rx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ cpu_ptr = kzalloc(rx->ring_size * sizeof(*rx->buffer_info),
+ GFP_KERNEL);
+ if (!cpu_ptr) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to allocate buffer info, channel = %d",
+ rx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ rx->buffer_info = (struct lan743x_rx_buffer_info *)cpu_ptr;
+
+ dma_ptr = 0;
+ cpu_ptr = pci_zalloc_consistent(
+ rx->adapter->pci.pdev,
+ sizeof(*rx->head_cpu_ptr), &dma_ptr);
+ if (!cpu_ptr) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Failed to allocate head pointer, channel = %d",
+ rx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ NETIF_ASSERT(adapter, drv, adapter->netdev, dma_ptr);
+ rx->head_cpu_ptr = cpu_ptr;
+ rx->head_dma_ptr = dma_ptr;
+ if ((rx->head_dma_ptr) & 0x3) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "head write back pointer is not DWORD aligned, channel = %d",
+ rx->channel_number);
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+ rx->last_head = 0;
+
+ for (element_index = 0; element_index < rx->ring_size;
+ element_index++) {
+ ret = lan743x_rx_allocate_ring_element(rx, element_index);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "failed to allocate rx ring element, element_index = %d",
+ element_index);
+ goto cleanup;
+ }
+ }
+ ret = 0;
+cleanup:
+ if (ret)
+ lan743x_rx_ring_cleanup(rx);
+
+ return ret;
+}
+
+static void lan743x_rx_ring_cleanup(struct lan743x_rx *rx)
+{
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, rx->adapter);
+
+ if ((rx->buffer_info) && (rx->ring_cpu_ptr)) {
+ int element_index;
+
+ for (element_index = 0; element_index < rx->ring_size;
+ element_index++)
+ lan743x_rx_release_ring_element(rx, element_index);
+ }
+
+ if (rx->head_cpu_ptr) {
+ pci_free_consistent(rx->adapter->pci.pdev,
+ sizeof(*rx->head_cpu_ptr),
+ (void *)(rx->head_cpu_ptr),
+ rx->head_dma_ptr);
+ rx->head_cpu_ptr = NULL;
+ rx->head_dma_ptr = 0;
+ }
+
+ kfree(rx->buffer_info);
+ rx->buffer_info = NULL;
+
+ if (rx->ring_cpu_ptr) {
+ pci_free_consistent(rx->adapter->pci.pdev,
+ rx->ring_allocation_size,
+ rx->ring_cpu_ptr,
+ rx->ring_dma_ptr);
+ rx->ring_allocation_size = 0;
+ rx->ring_cpu_ptr = NULL;
+ rx->ring_dma_ptr = 0;
+ }
+
+ rx->ring_size = 0;
+ rx->last_head = 0;
+}
+
+static int lan743x_rx_init(struct lan743x_rx *rx,
+ struct lan743x_adapter *adapter, int rx_channel)
+{
+ int ret = -ENODEV;
+
+ memset(rx, 0, sizeof(*rx));
+ NETIF_ASSERT(adapter, probe, adapter->netdev,
+ (rx_channel >= 0) &&
+ (rx_channel < LAN743X_NUMBER_OF_RX_CHANNELS));
+
+ rx->adapter = adapter;
+ rx->channel_number = -1;
+
+ ret = lan743x_dmac_reserve_rx_channel(adapter, rx_channel);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "Failed to reserve rx channel %d",
+ rx_channel);
+ goto cleanup;
+ }
+ rx->channel_number = rx_channel;
+
+ ret = 0;
+
+cleanup:
+ if (ret)
+ lan743x_rx_cleanup(rx);
+ return ret;
+}
+
+static void lan743x_rx_cleanup(struct lan743x_rx *rx)
+{
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ if (rx->channel_number >= 0) {
+ lan743x_dmac_release_rx_channel(adapter, rx->channel_number);
+ rx->channel_number = -1;
+ }
+
+ memset(rx, 0, sizeof(*rx));
+}
+
+static int lan743x_rx_open(struct lan743x_rx *rx)
+{
+ int ret = -ENODEV;
+ struct lan743x_adapter *adapter = rx->adapter;
+ u32 data = 0;
+
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ (rx->channel_number >= 0) &&
+ (rx->channel_number < LAN743X_NUMBER_OF_RX_CHANNELS));
+
+ ret = lan743x_rx_ring_init(rx);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Rx channel %d, ring initialization failed",
+ rx->channel_number);
+ goto cleanup;
+ }
+ rx->flags |= RX_FLAG_RING_ALLOCATED;
+
+ NETIF_ASSERT(adapter, ifup, adapter->netdev, rx->ring_size >= 1);
+
+ netif_napi_add(rx->adapter->netdev,
+ &rx->napi, lan743x_rx_napi_poll,
+ rx->ring_size - 1);
+ rx->flags |= RX_FLAG_NAPI_ADDED;
+
+ ret = lan743x_dmac_rx_reset(adapter, rx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Failed to reset rx dmac, rx_channel = %d",
+ rx->channel_number);
+ goto cleanup;
+ }
+
+ /* set ring base address */
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ !((rx->ring_dma_ptr) & 0x3));
+ lan743x_csr_write(adapter,
+ RX_BASE_ADDRH(rx->channel_number),
+ DMA_ADDR_HIGH32(rx->ring_dma_ptr));
+ lan743x_csr_write(adapter,
+ RX_BASE_ADDRL(rx->channel_number),
+ DMA_ADDR_LOW32(rx->ring_dma_ptr));
+
+ /* set rx write back address */
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ !((rx->head_dma_ptr) & 0x3));
+ lan743x_csr_write(adapter,
+ RX_HEAD_WRITEBACK_ADDRH(rx->channel_number),
+ DMA_ADDR_HIGH32(rx->head_dma_ptr));
+ lan743x_csr_write(adapter,
+ RX_HEAD_WRITEBACK_ADDRL(rx->channel_number),
+ DMA_ADDR_LOW32(rx->head_dma_ptr));
+
+ /* set RX_CFG_A */
+ lan743x_csr_write(adapter,
+ RX_CFG_A(rx->channel_number),
+ RX_CFG_A_RX_HP_WB_EN_);
+
+ /* set RX_CFG_B */
+ data = lan743x_csr_read(adapter, RX_CFG_B(rx->channel_number));
+ data &= ~RX_CFG_B_RX_PAD_MASK_;
+ if (!RX_HEAD_PADDING)
+ data |= RX_CFG_B_RX_PAD_0_;
+ else
+ data |= RX_CFG_B_RX_PAD_2_;
+ data &= ~RX_CFG_B_RX_RING_LEN_MASK_;
+ data |= ((rx->ring_size) & RX_CFG_B_RX_RING_LEN_MASK_);
+ data |= RX_CFG_B_TS_ALL_RX_;
+ lan743x_csr_write(adapter, RX_CFG_B(rx->channel_number), data);
+
+ lan743x_csr_write(adapter, RX_TAIL(rx->channel_number),
+ ((u32)(rx->ring_size - 1)));
+ rx->last_head = lan743x_csr_read(adapter, RX_HEAD(rx->channel_number));
+ if (rx->last_head) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev, "last_head != 0");
+ ret = -EIO;
+ goto cleanup;
+ }
+
+ napi_enable(&rx->napi);
+ lan743x_csr_write(adapter, INT_EN_SET,
+ INT_BIT_DMA_RX_(rx->channel_number));
+ lan743x_csr_write(adapter, DMAC_INT_STS,
+ DMAC_INT_BIT_RXFRM_(rx->channel_number));
+ lan743x_csr_write(adapter, DMAC_INT_EN_SET,
+ DMAC_INT_BIT_RXFRM_(rx->channel_number));
+ rx->flags |= RX_FLAG_ISR_ENABLED;
+
+ ret = lan743x_dmac_rx_start(adapter, rx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Failed to start rx channel %d, first",
+ rx->channel_number);
+ goto cleanup;
+ }
+ rx->flags |= RX_FLAG_DMAC_STARTED;
+
+ /* initialize fifo */
+ NETIF_ASSERT(adapter, ifup, adapter->netdev,
+ !(rx->flags & RX_FLAG_FIFO_ENABLED));
+ ret = lan743x_fct_rx_reset(adapter, rx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Failed to reset rx fifo, rx_channel = %d",
+ rx->channel_number);
+ goto cleanup;
+ }
+
+ /* enable fifo */
+ ret = lan743x_fct_rx_enable(adapter, rx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "Failed to enable rx fifo, rx_channel = %d",
+ rx->channel_number);
+ goto cleanup;
+ }
+ rx->flags |= RX_FLAG_FIFO_ENABLED;
+
+ /* enable mac */
+ ret = lan743x_mac_rx_enable(adapter, rx->channel_number);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "failed to enable mac, rx_channel = %d",
+ rx->channel_number);
+ goto cleanup;
+ }
+ rx->flags |= RX_FLAG_MAC_ENABLED;
+
+ ret = 0;
+cleanup:
+ if (ret)
+ lan743x_rx_close(rx);
+ return ret;
+}
+
+static void lan743x_rx_close(struct lan743x_rx *rx)
+{
+ struct lan743x_adapter *adapter = rx->adapter;
+
+ if (rx->flags & RX_FLAG_MAC_ENABLED) {
+ lan743x_mac_rx_disable(adapter, rx->channel_number);
+ rx->flags &= ~RX_FLAG_MAC_ENABLED;
+ }
+
+ if (rx->flags & RX_FLAG_FIFO_ENABLED) {
+ lan743x_fct_rx_disable(adapter, rx->channel_number);
+ rx->flags &= ~RX_FLAG_FIFO_ENABLED;
+ }
+
+ if (rx->flags & RX_FLAG_DMAC_STARTED) {
+ lan743x_dmac_rx_stop(adapter, rx->channel_number);
+ rx->flags &= ~RX_FLAG_DMAC_STARTED;
+ }
+
+ if (rx->flags & RX_FLAG_ISR_ENABLED) {
+ lan743x_csr_write(adapter,
+ DMAC_INT_EN_CLR,
+ DMAC_INT_BIT_RXFRM_(rx->channel_number));
+ lan743x_csr_write(adapter, INT_EN_CLR,
+ INT_BIT_DMA_RX_(rx->channel_number));
+ napi_disable(&rx->napi);
+ rx->flags &= ~RX_FLAG_ISR_ENABLED;
+ }
+
+ if (rx->flags & RX_FLAG_NAPI_ADDED) {
+ netif_napi_del(&rx->napi);
+ rx->flags &= ~RX_FLAG_NAPI_ADDED;
+ }
+
+ if (rx->flags & RX_FLAG_RING_ALLOCATED) {
+ lan743x_rx_ring_cleanup(rx);
+ rx->flags &= ~RX_FLAG_RING_ALLOCATED;
+ }
+}
+
+/* NETDEV */
+
+static int lan743x_netdev_close(struct net_device *netdev)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ NETIF_INFO(adapter, ifdown, adapter->netdev, "LAN743x_closing");
+
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_TX(0)) {
+ lan743x_tx_close(&adapter->tx[0]);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_TX(0);
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_RX(0)) {
+ lan743x_rx_close(&adapter->rx[0]);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_RX(0);
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_DMAC) {
+ lan743x_dmac_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_DMAC;
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_FCT) {
+ lan743x_fct_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_FCT;
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_RFE) {
+ lan743x_rfe_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_RFE;
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_PTP) {
+ lan743x_ptp_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_PTP;
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_PHY) {
+ lan743x_phy_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_PHY;
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_MAC) {
+ lan743x_mac_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_MAC;
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_GPIO) {
+ lan743x_gpio_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_GPIO;
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_DP) {
+ lan743x_dp_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_DP;
+ }
+ if (adapter->open_flags & LAN743X_COMPONENT_FLAG_INTR) {
+ lan743x_intr_close(adapter);
+ adapter->open_flags &= ~LAN743X_COMPONENT_FLAG_INTR;
+ }
+ return 0;
+}
+
+static int lan743x_netdev_open(struct net_device *netdev)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ int ret;
+
+ NETIF_ASSERT(adapter, ifup, adapter->netdev, !adapter->open_flags);
+
+ ret = lan743x_intr_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "intr opened failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_INTR;
+
+ ret = lan743x_dp_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev, "dp_open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_DP;
+
+ ret = lan743x_gpio_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "gpio_open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_GPIO;
+
+ ret = lan743x_mac_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev, "mac_open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_MAC;
+
+ ret = lan743x_phy_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev, "phy_open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_PHY;
+
+ ret = lan743x_ptp_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev, "ptp_open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_PTP;
+
+ ret = lan743x_rfe_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev, "rfe_open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_RFE;
+
+ ret = lan743x_fct_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev, "fct_open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_FCT;
+
+ ret = lan743x_dmac_open(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "dmac_open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_DMAC;
+
+ ret = lan743x_rx_open(&adapter->rx[0]);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "rx[0] open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_RX(0);
+
+ ret = lan743x_tx_open(&adapter->tx[0]);
+ if (ret) {
+ NETIF_ERROR(adapter, ifup, adapter->netdev,
+ "tx[0] open failed");
+ goto clean_up;
+ }
+ adapter->open_flags |= LAN743X_COMPONENT_FLAG_TX(0);
+
+ NETIF_INFO(adapter, ifup, adapter->netdev,
+ "LAN743x opened successfully");
+
+clean_up:
+ if (ret) {
+ NETIF_WARNING(adapter, ifup, adapter->netdev,
+ "Error opening LAN743x, performing cleanup");
+ lan743x_netdev_close(netdev);
+ }
+ return ret;
+}
+
+static netdev_tx_t lan743x_netdev_xmit_frame(
+ struct sk_buff *skb, struct net_device *netdev)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ netdev->stats.tx_packets++;
+ return lan743x_tx_xmit_frame(&adapter->tx[0], skb);
+}
+
+static int lan743x_netdev_ioctl(
+ struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ struct hwtstamp_config config;
+ int ret = 0;
+ int index;
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+ if (cmd != SIOCSHWTSTAMP) {
+ int ret = phy_mii_ioctl(netdev->phydev, ifr, cmd);
+
+ if (ret == -EINVAL)
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "operation not supported");
+ return ret;
+ }
+ if (!ifr) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "SIOCSHWTSTAMP, ifr == NULL");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ if (config.flags) {
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ "ignoring hwtstamp_config.flags == 0x%08X, expected 0",
+ config.flags);
+ }
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ for (index = 0; index < LAN743X_NUMBER_OF_TX_CHANNELS;
+ index++)
+ lan743x_tx_set_timestamping_enable(&adapter->tx[index],
+ false);
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " tx_type = HWTSTAMP_TX_OFF");
+ break;
+ case HWTSTAMP_TX_ON:
+ for (index = 0; index < LAN743X_NUMBER_OF_TX_CHANNELS;
+ index++)
+ lan743x_tx_set_timestamping_enable(&adapter->tx[index],
+ true);
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " tx_type = HWTSTAMP_TX_ON");
+ break;
+ default:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " tx_type = %d, UNKNOWN", config.tx_type);
+ ret = -EINVAL;
+ break;
+ }
+ /* currently the driver timestamps all incoming packets
+ * so no special setting is require
+ */
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_NONE");
+ break;
+ case HWTSTAMP_FILTER_ALL:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_ALL");
+ break;
+ case HWTSTAMP_FILTER_SOME:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_SOME");
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT");
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC");
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_SYNC");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC");
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ " rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ");
+ break;
+ default:
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ " rx_filter = %d, UNKNOWN", config.rx_filter);
+ NETIF_WARNING(adapter, drv, adapter->netdev,
+ " assuming rx_filter = HWTSTAMP_FILTER_ALL");
+ /* treat this like HWTSTAMP_FILTER_ALL */
+ break;
+ }
+ if (!ret)
+ return copy_to_user(ifr->ifr_data, &config,
+ sizeof(config)) ? -EFAULT : 0;
+ return ret;
+}
+
+static void lan743x_netdev_set_multicast(struct net_device *netdev)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, netdev);
+ adapter = netdev_priv(netdev);
+ lan743x_rfe_set_multicast(adapter);
+}
+
+static int lan743x_netdev_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ int ret = 0;
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ NETIF_INFO(adapter, drv, adapter->netdev, "new_mtu = %d", new_mtu);
+ ret = lan743x_mac_set_mtu(adapter, new_mtu);
+ if (!ret)
+ netdev->mtu = new_mtu;
+ return ret;
+}
+
+static struct net_device_stats *lan743x_netdev_get_stats(struct net_device *nd)
+{
+ struct lan743x_adapter *adapter = NULL;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, nd);
+ adapter = netdev_priv(nd);
+ return mac_get_stats(adapter);
+}
+
+static int lan743x_netdev_set_mac_address(struct net_device *netdev,
+ void *addr)
+{
+ struct lan743x_adapter *adapter = NULL;
+ struct sockaddr *sock_addr = addr;
+
+ NETIF_ASSERT(adapter, drv, adapter->netdev, netdev);
+
+ if (netif_running(netdev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(sock_addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ ether_addr_copy(netdev->dev_addr, sock_addr->sa_data);
+
+ adapter = netdev_priv(netdev);
+ lan743x_mac_set_address(adapter, sock_addr->sa_data);
+ lan743x_rfe_update_mac_address(adapter);
+
+ return 0;
+}
+
+static const struct net_device_ops lan743x_netdev_ops = {
+ .ndo_open = lan743x_netdev_open,
+ .ndo_stop = lan743x_netdev_close,
+ .ndo_start_xmit = lan743x_netdev_xmit_frame,
+ .ndo_do_ioctl = lan743x_netdev_ioctl,
+ .ndo_set_rx_mode = lan743x_netdev_set_multicast,
+ .ndo_change_mtu = lan743x_netdev_change_mtu,
+ .ndo_get_stats = lan743x_netdev_get_stats,
+ .ndo_set_mac_address = lan743x_netdev_set_mac_address,
+};
+
+/* ETHTOOL */
+static const char lan743x_gstrings[][ETH_GSTRING_LEN] = {
+ "RX FCS Errors",
+ "RX Alignment Errors",
+ "Rx Fragment Errors",
+ "RX Jabber Errors",
+ "RX Undersize Frame Errors",
+ "RX Oversize Frame Errors",
+ "RX Dropped Frames",
+ "RX Unicast Byte Count",
+ "RX Broadcast Byte Count",
+ "RX Multicast Byte Count",
+ "RX Unicast Frames",
+ "RX Broadcast Frames",
+ "RX Multicast Frames",
+ "RX Pause Frames",
+ "RX 64 Byte Frames",
+ "RX 65 - 127 Byte Frames",
+ "RX 128 - 255 Byte Frames",
+ "RX 256 - 511 Bytes Frames",
+ "RX 512 - 1023 Byte Frames",
+ "RX 1024 - 1518 Byte Frames",
+ "RX Greater 1518 Byte Frames",
+ "RX Total Frames",
+ "EEE RX LPI Transitions",
+ "EEE RX LPI Time",
+ "RX Counter Rollover Status",
+ "TX FCS Errors",
+ "TX Excess Deferral Errors",
+ "TX Carrier Errors",
+ "TX Bad Byte Count",
+ "TX Single Collisions",
+ "TX Multiple Collisions",
+ "TX Excessive Collision",
+ "TX Late Collisions",
+ "TX Unicast Byte Count",
+ "TX Broadcast Byte Count",
+ "TX Multicast Byte Count",
+ "TX Unicast Frames",
+ "TX Broadcast Frames",
+ "TX Multicast Frames",
+ "TX Pause Frames",
+ "TX 64 Byte Frames",
+ "TX 65 - 127 Byte Frames",
+ "TX 128 - 255 Byte Frames",
+ "TX 256 - 511 Bytes Frames",
+ "TX 512 - 1023 Byte Frames",
+ "TX 1024 - 1518 Byte Frames",
+ "TX Greater 1518 Byte Frames",
+ "TX Total Frames",
+ "EEE TX LPI Transitions",
+ "EEE TX LPI Time",
+ "TX Counter Rollover Status",
+};
+
+static const u32 lan743x_stat_addr[] = {
+ STAT_RX_FCS_ERRORS,
+ STAT_RX_ALIGNMENT_ERRORS,
+ STAT_RX_FRAGMENT_ERRORS,
+ STAT_RX_JABBER_ERRORS,
+ STAT_RX_UNDERSIZE_FRAME_ERRORS,
+ STAT_RX_OVERSIZE_FRAME_ERRORS,
+ STAT_RX_DROPPED_FRAMES,
+ STAT_RX_UNICAST_BYTE_COUNT,
+ STAT_RX_BROADCAST_BYTE_COUNT,
+ STAT_RX_MULTICAST_BYTE_COUNT,
+ STAT_RX_UNICAST_FRAMES,
+ STAT_RX_BROADCAST_FRAMES,
+ STAT_RX_MULTICAST_FRAMES,
+ STAT_RX_PAUSE_FRAMES,
+ STAT_RX_64_BYTE_FRAMES,
+ STAT_RX_65_127_BYTE_FRAMES,
+ STAT_RX_128_255_BYTE_FRAMES,
+ STAT_RX_256_511_BYTES_FRAMES,
+ STAT_RX_512_1023_BYTE_FRAMES,
+ STAT_RX_1024_1518_BYTE_FRAMES,
+ STAT_RX_GREATER_1518_BYTE_FRAMES,
+ STAT_RX_TOTAL_FRAMES,
+ STAT_EEE_RX_LPI_TRANSITIONS,
+ STAT_EEE_RX_LPI_TIME,
+ STAT_RX_COUNTER_ROLLOVER_STATUS,
+ STAT_TX_FCS_ERRORS,
+ STAT_TX_EXCESS_DEFERRAL_ERRORS,
+ STAT_TX_CARRIER_ERRORS,
+ STAT_TX_BAD_BYTE_COUNT,
+ STAT_TX_SINGLE_COLLISIONS,
+ STAT_TX_MULTIPLE_COLLISIONS,
+ STAT_TX_EXCESSIVE_COLLISION,
+ STAT_TX_LATE_COLLISIONS,
+ STAT_TX_UNICAST_BYTE_COUNT,
+ STAT_TX_BROADCAST_BYTE_COUNT,
+ STAT_TX_MULTICAST_BYTE_COUNT,
+ STAT_TX_UNICAST_FRAMES,
+ STAT_TX_BROADCAST_FRAMES,
+ STAT_TX_MULTICAST_FRAMES,
+ STAT_TX_PAUSE_FRAMES,
+ STAT_TX_64_BYTE_FRAMES,
+ STAT_TX_65_127_BYTE_FRAMES,
+ STAT_TX_128_255_BYTE_FRAMES,
+ STAT_TX_256_511_BYTES_FRAMES,
+ STAT_TX_512_1023_BYTE_FRAMES,
+ STAT_TX_1024_1518_BYTE_FRAMES,
+ STAT_TX_GREATER_1518_BYTE_FRAMES,
+ STAT_TX_TOTAL_FRAMES,
+ STAT_EEE_TX_LPI_TRANSITIONS,
+ STAT_EEE_TX_LPI_TIME,
+ STAT_TX_COUNTER_ROLLOVER_STATUS
+};
+
+static void lan743x_ethtool_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info,
+ pci_name(adapter->pci.pdev), sizeof(info->bus_info));
+}
+
+static u32 lan743x_ethtool_get_msglevel(struct net_device *netdev)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "get_msglevel: msg_enable == 0x%08X",
+ adapter->msg_enable);
+ return adapter->msg_enable;
+}
+
+static void lan743x_ethtool_set_msglevel(struct net_device *netdev,
+ u32 msglevel)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ adapter->msg_enable = msglevel;
+ NETIF_INFO(adapter, drv, adapter->netdev,
+ "set_msglevel: msg_enable == 0x%08X",
+ adapter->msg_enable);
+}
+
+static int lan743x_ethtool_get_eeprom_len(struct net_device *netdev)
+{
+ return 0;
+}
+
+static void lan743x_ethtool_get_strings(struct net_device *netdev,
+ u32 stringset, u8 *data)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, lan743x_gstrings, sizeof(lan743x_gstrings));
+ break;
+ }
+}
+
+static void lan743x_ethtool_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ int i;
+ u32 buf;
+
+ for (i = 0; i < (sizeof(lan743x_stat_addr) / (sizeof(u32))); i++) {
+ buf = lan743x_csr_read(adapter, lan743x_stat_addr[i]);
+ data[i] = (u64)buf;
+ }
+}
+
+static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(lan743x_gstrings);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int lan743x_ethtool_get_ts_info(struct net_device *netdev,
+ struct ethtool_ts_info *ts_info)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+ ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+#ifdef CONFIG_PTP_1588_CLOCK
+ ts_info->phc_index = lan743x_ptp_get_clock_index(adapter);
+#else
+ ts_info->phc_index = -1;
+#endif
+ ts_info->tx_types = BIT(HWTSTAMP_TX_OFF) |
+ BIT(HWTSTAMP_TX_ON);
+ ts_info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+ BIT(HWTSTAMP_FILTER_ALL);
+ return 0;
+}
+
+static int lan743x_ethtool_get_eee(struct net_device *netdev,
+ struct ethtool_eee *eee)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ struct phy_device *phydev = netdev->phydev;
+ u32 buf;
+ int ret;
+
+ if (!phydev)
+ return -EIO;
+ if (!phydev->drv) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Missing PHY Driver");
+ return -EIO;
+ }
+
+ ret = phy_ethtool_get_eee(phydev, eee);
+ if (ret < 0)
+ return ret;
+
+ buf = lan743x_csr_read(adapter, MAC_CR);
+ if (buf & MAC_CR_EEE_EN_) {
+ eee->eee_enabled = true;
+ eee->eee_active = !!(eee->advertised & eee->lp_advertised);
+ eee->tx_lpi_enabled = true;
+ /* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */
+ buf = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT);
+ eee->tx_lpi_timer = buf;
+ } else {
+ eee->eee_enabled = false;
+ eee->eee_active = false;
+ eee->tx_lpi_enabled = false;
+ eee->tx_lpi_timer = 0;
+ }
+
+ return 0;
+}
+
+static int lan743x_ethtool_set_eee(struct net_device *netdev,
+ struct ethtool_eee *eee)
+{
+ struct lan743x_adapter *adapter = netdev_priv(netdev);
+ struct phy_device *phydev = NULL;
+ u32 buf = 0;
+
+ if (!netdev)
+ return -EINVAL;
+ adapter = netdev_priv(netdev);
+ if (!adapter)
+ return -EINVAL;
+ phydev = netdev->phydev;
+ if (!phydev)
+ return -EIO;
+ if (!phydev->drv) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "Missing PHY Driver");
+ return -EIO;
+ }
+
+ if (eee->eee_enabled) {
+ buf = lan743x_csr_read(adapter, MAC_CR);
+ buf |= MAC_CR_EEE_EN_;
+ lan743x_csr_write(adapter, MAC_CR, buf);
+
+ phy_ethtool_set_eee(phydev, eee);
+
+ buf = (u32)eee->tx_lpi_timer;
+ lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT, buf);
+ NETIF_INFO(adapter, drv, adapter->netdev, "Enabled EEE");
+ } else {
+ buf = lan743x_csr_read(adapter, MAC_CR);
+ buf &= ~MAC_CR_EEE_EN_;
+ lan743x_csr_write(adapter, MAC_CR, buf);
+ NETIF_INFO(adapter, drv, adapter->netdev, "Disabled EEE");
+ }
+
+ return 0;
+}
+
+static const struct ethtool_ops lan743x_ethtool_ops = {
+ .get_drvinfo = lan743x_ethtool_get_drvinfo,
+ .get_msglevel = lan743x_ethtool_get_msglevel,
+ .set_msglevel = lan743x_ethtool_set_msglevel,
+ .get_link = ethtool_op_get_link,
+
+ .get_eeprom_len = lan743x_ethtool_get_eeprom_len,
+ .get_strings = lan743x_ethtool_get_strings,
+ .get_ethtool_stats = lan743x_ethtool_get_ethtool_stats,
+ .get_sset_count = lan743x_ethtool_get_sset_count,
+ .get_ts_info = lan743x_ethtool_get_ts_info,
+ .get_eee = lan743x_ethtool_get_eee,
+ .set_eee = lan743x_ethtool_set_eee,
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings
+};
+
+static void lan743x_device_cleanup(struct lan743x_adapter *adapter)
+{
+ struct net_device *netdev = NULL;
+
+ NETIF_INFO(adapter, drv, adapter->netdev, "performing cleanup");
+
+ if (adapter->init_flags & LAN743X_INIT_FLAG_NETDEV_REGISTERED) {
+ unregister_netdev(adapter->netdev);
+ adapter->init_flags &= ~LAN743X_INIT_FLAG_NETDEV_REGISTERED;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_TX(0)) {
+ lan743x_tx_cleanup(&adapter->tx[0]);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_TX(0);
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_RX(0)) {
+ lan743x_rx_cleanup(&adapter->rx[0]);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_RX(0);
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_DMAC) {
+ lan743x_dmac_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_DMAC;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_FCT) {
+ lan743x_fct_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_FCT;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_RFE) {
+ lan743x_rfe_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_RFE;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_PTP) {
+ lan743x_ptp_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_PTP;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_PHY) {
+ lan743x_phy_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_PHY;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_MAC) {
+ lan743x_mac_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_MAC;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_GPIO) {
+ lan743x_gpio_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_GPIO;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_DP) {
+ lan743x_dp_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_DP;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_INTR) {
+ lan743x_intr_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_INTR;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_CSR) {
+ lan743x_csr_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_CSR;
+ }
+ if (adapter->init_flags & LAN743X_COMPONENT_FLAG_PCI) {
+ lan743x_pci_cleanup(adapter);
+ adapter->init_flags &= ~LAN743X_COMPONENT_FLAG_PCI;
+ }
+
+ netdev = adapter->netdev;
+ memset(adapter, 0, sizeof(struct lan743x_adapter));
+ free_netdev(netdev);
+}
+
+/* lan743x_pcidev_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @id: entry in lan743x_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int lan743x_pcidev_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct net_device *netdev = NULL;
+ struct lan743x_adapter *adapter = NULL;
+ int ret = -ENODEV;
+
+ NETIF_ASSERT(adapter, probe, adapter->netdev, pdev);
+
+ netdev = alloc_etherdev(sizeof(struct lan743x_adapter));
+ if (!netdev) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "alloc_etherdev returned NULL");
+ ret = -ENOMEM;
+ goto clean_up;
+ }
+
+ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ if (!adapter) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "netdev_priv returned NULL");
+ ret = -ENOMEM;
+ goto clean_up;
+ }
+ memset(adapter, 0, sizeof(struct lan743x_adapter));
+ adapter->netdev = netdev;
+ adapter->init_flags = 0;
+ adapter->open_flags = 0;
+ adapter->msg_enable = msg_enable;
+ netdev->max_mtu = LAN743X_MAX_FRAME_SIZE;
+
+ ret = lan743x_pci_init(adapter, pdev);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_pci_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_PCI;
+
+ ret = lan743x_csr_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_csr_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_CSR;
+
+ ret = lan743x_intr_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, drv, adapter->netdev,
+ "lan743x_intr_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_INTR;
+
+ ret = lan743x_dp_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_dp_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_DP;
+
+ ret = lan743x_gpio_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_gpio_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_GPIO;
+
+ ret = lan743x_mac_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_mac_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_MAC;
+
+ ret = lan743x_phy_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_phy_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_PHY;
+
+ ret = lan743x_ptp_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_ptp_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_PTP;
+
+ ret = lan743x_rfe_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_rfe_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_RFE;
+
+ ret = lan743x_fct_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_fct_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_FCT;
+
+ ret = lan743x_dmac_init(adapter);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_dmac_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_DMAC;
+
+ ret = lan743x_rx_init(&adapter->rx[0], adapter, 0);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_rx_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_RX(0);
+
+ ret = lan743x_tx_init(&adapter->tx[0], adapter, 0);
+ if (ret) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "lan743x_tx_init failed, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_COMPONENT_FLAG_TX(0);
+
+ netdev->netdev_ops = &lan743x_netdev_ops;
+ netdev->ethtool_ops = &lan743x_ethtool_ops;
+ netdev->features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM;
+ netdev->hw_features = netdev->features;
+
+ strncpy(netdev->name, "eth%d", sizeof(netdev->name));
+ ret = register_netdev(netdev);
+ if (ret < 0) {
+ NETIF_ERROR(adapter, probe, adapter->netdev,
+ "failed to register net device, ret = %d", ret);
+ goto clean_up;
+ }
+ adapter->init_flags |= LAN743X_INIT_FLAG_NETDEV_REGISTERED;
+
+ NETIF_INFO(adapter, probe, adapter->netdev, "Probe succeeded");
+ ret = 0;
+
+clean_up:
+ if (ret && adapter) {
+ NETIF_WARNING(adapter, probe, adapter->netdev,
+ "Incomplete initialization, performing clean up");
+ lan743x_device_cleanup(adapter);
+ }
+ return ret;
+}
+
+/**
+ * lan743x_pcidev_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * this is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. This could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void lan743x_pcidev_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = NULL;
+ struct lan743x_adapter *adapter = NULL;
+
+ netdev = pci_get_drvdata(pdev);
+ adapter = netdev_priv(netdev);
+ lan743x_device_cleanup(adapter);
+}
+
+static const struct pci_device_id lan743x_pcidev_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7430) },
+ { 0, }
+};
+
+static struct pci_driver lan743x_pcidev_driver = {
+ .name = DRIVER_NAME,
+ .id_table = lan743x_pcidev_tbl,
+ .probe = lan743x_pcidev_probe,
+ .remove = lan743x_pcidev_remove,
+};
+
+static int __init lan743x_module_init(void)
+{
+ int result = 0;
+
+ pr_info(DRIVER_DESC " %s\n", DRIVER_VERSION);
+ pr_info("module parameter\n");
+ pr_info(" msg_enable = 0x%04X\n", msg_enable);
+
+ result = pci_register_driver(&lan743x_pcidev_driver);
+ if (result)
+ pr_warn("pci_register_driver returned error code, %d\n",
+ result);
+ return result;
+}
+
+module_init(lan743x_module_init);
+
+static void __exit lan743x_module_exit(void)
+{
+ pci_unregister_driver(&lan743x_pcidev_driver);
+}
+
+module_exit(lan743x_module_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/net/ethernet/microchip/lan743x.h b/drivers/net/ethernet/microchip/lan743x.h
new file mode 100644
index 0000000..8cf4323
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x.h
@@ -0,0 +1,1417 @@
+/*
+ * Copyright (C) 2017 Microchip Technology
+ *
+ * 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 Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _LAN743X_H
+#define _LAN743X_H
+
+/* Register Definitions */
+#define ID_REV (0x00)
+#define ID_REV_CHIP_ID_MASK_ (0xFFFF0000)
+#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF)
+#define ID_REV_CHIP_ID_7430_ (0x7430)
+
+#define FPGA_REV (0x04)
+#define FPGA_REV_MINOR_MASK_ (0x0000FF00)
+#define FPGA_REV_MAJOR_MASK_ (0x000000FF)
+
+#define HW_CFG (0x010)
+#define HW_CFG_INVERT_LED3_POLARITY BIT(31)
+#define HW_CFG_INVERT_LED2_POLARITY BIT(30)
+#define HW_CFG_INVERT_LED1_POLARITY BIT(29)
+#define HW_CFG_INVERT_LED0_POLARITY BIT(28)
+#define HW_CFG_CLK125_EN_ BIT(25)
+#define HW_CFG_REFCLK25_EN_ BIT(24)
+#define HW_CFG_LED3_EN_ BIT(23)
+#define HW_CFG_LED2_EN_ BIT(22)
+#define HW_CFG_LED1_EN_ BIT(21)
+#define HW_CFG_LED0_EN_ BIT(20)
+#define HW_CFG_EEE_PHY_LUSU_ BIT(17)
+#define HW_CFG_EEE_TSU_ BIT(16)
+#define HW_CFG_RST_PROTECT_ BIT(12)
+#define HW_CFG_RL_TYPE_EEPROM_UIT_CSR_ BIT(11)
+#define HW_CFG_RL_TYPE_EEPROM_UIT_PCIE_ BIT(10)
+#define HW_CFG_RL_TYPE_LED_CONFIG_ BIT(9)
+#define HW_CFG_RL_TYPE_MAC_CONFIG_ BIT(8)
+#define HW_CFG_RL_TYPE_PCI_CONFIG_ BIT(7)
+#define HW_CFG_RL_TYPE_MAC_ADDR_ BIT(6)
+#define HW_CFG_EE_OTP_DL_ BIT(5)
+#define HW_CFG_EE_OTP_RELOAD_ BIT(4)
+#define HW_CFG_ETC_ BIT(3)
+#define HW_CFG_EEP_GPIO_LED_PIN_DIS_ BIT(2)
+#define HW_CFG_LRST_ BIT(1)
+#define HW_CFG_SRST_ BIT(0)
+
+#define PMT_CTL (0x014)
+#define PMT_CTL_ETH_PHY_D3_COLD_OVR_ BIT(27)
+#define PMT_CTL_MAC_D3_TX_CLK_OVR_ BIT(26)
+#define PMT_CTL_MAC_D3_RX_CLK_OVR_ BIT(25)
+#define PMT_CTL_ETH_PHY_EDPD_PLL_CTL_ BIT(24)
+#define PMT_CTL_ETH_PHY_D3_OVR_ BIT(23)
+#define PMT_CTL_INT_D3_CLK_OVR_ BIT(22)
+#define PMT_CTL_DMAC_D3_CLK_OVR_ BIT(21)
+#define PMT_CTL_1588_D3_CLK_OVR_ BIT(20)
+#define PMT_CTL_MAC_D3_CLK_OVR_ BIT(19)
+#define PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ BIT(18)
+#define PMT_CTL_TX_FCT_LSO_D3_CLK_OVR_ BIT(17)
+#define PMT_CTL_OTP_EEPROM_D3_CLK_OVR_ BIT(16)
+#define PMT_CTL_GPIO_WAKEUP_EN_ BIT(15)
+#define PMT_CTL_GPIO_WUPS_ BIT(14)
+#define PMT_CTL_EEE_WAKEUP_EN_ BIT(13)
+#define PMT_CTL_EEE_WUPS_ BIT(12)
+#define PMT_CTL_RES_CLR_WKP_MASK_ (0x00000300)
+#define PMT_CTL_RES_CLR_WKP_STS_ BIT(9)
+#define PMT_CTL_RES_CLR_WKP_EN_ BIT(8)
+#define PMT_CTL_READY_ BIT(7)
+#define PMT_CTL_EXT_PHY_RDY_EN_ BIT(5)
+#define PMT_CTL_ETH_PHY_RST_ BIT(4)
+#define PMT_CTL_WOL_EN_ BIT(3)
+#define PMT_CTL_ETH_PHY_WAKE_EN_ BIT(2)
+#define PMT_CTL_WUPS_MASK_ (0x00000003)
+#define PMT_CTL_WUPS_MLT_ (0x00000003)
+#define PMT_CTL_WUPS_MAC_ (0x00000002)
+#define PMT_CTL_WUPS_PHY_ (0x00000001)
+
+#define DP_SEL (0x024)
+#define DP_SEL_DPRDY_ BIT(31)
+#define DP_SEL_MASK_ (0x0000001F)
+#define DP_SEL_PCIE_DRCV_RAM (0x00000016)
+#define DP_SEL_PCIE_HRCV_RAM (0x00000015)
+#define DP_SEL_PCIE_SOT_RAM (0x00000014)
+#define DP_SEL_PCIE_RETRY_RAM (0x00000013)
+#define DP_SEL_DMAC_TX_RAM_0 (0x0000000F)
+#define DP_SEL_DMAC_RX_RAM_3 (0x0000000E)
+#define DP_SEL_DMAC_RX_RAM_2 (0x0000000D)
+#define DP_SEL_DMAC_RX_RAM_1 (0x0000000C)
+#define DP_SEL_DMAC_RX_RAM_0 (0x0000000B)
+#define DP_SEL_DMAC_REORDER_BUFFER (0x0000000A)
+#define DP_SEL_FCT_TX_RAM_0 (0x00000006)
+#define DP_SEL_FCT_RX_RAM_3 (0x00000005)
+#define DP_SEL_FCT_RX_RAM_2 (0x00000004)
+#define DP_SEL_FCT_RX_RAM_1 (0x00000003)
+#define DP_SEL_FCT_RX_RAM_0 (0x00000002)
+#define DP_SEL_RFE_RAM (0x00000001)
+#define DP_SEL_LSO_RAM (0x00000000)
+
+#define DP_SEL_VHF_HASH_LEN (16)
+#define DP_SEL_VHF_VLAN_LEN (128)
+
+#define DP_CMD (0x028)
+#define DP_CMD_WRITE_ (0x00000001)
+#define DP_CMD_READ_ (0x00000000)
+
+#define DP_ADDR (0x02C)
+#define DP_ADDR_MASK_ (0x00003FFF)
+
+#define DP_DATA_0 (0x030)
+
+#define DP_DATA_1 (0x034)
+
+#define DP_DATA_2 (0x038)
+
+#define DP_DATA_3 (0x03C)
+
+#define GPIO_CFG0 (0x050)
+#define GPIO_CFG0_GPIO_DIR_MASK_ (0x0FFF0000)
+#define GPIO_CFG0_GPIO_DIR_(bit) BIT(16 + (bit))
+#define GPIO_CFG0_GPIO_DATA_MASK_ (0x00000FFF)
+#define GPIO_CFG0_GPIO_DATA_(bit) BIT(0 + (bit))
+
+#define GPIO_CFG1 (0x054)
+#define GPIO_CFG1_GPIOEN_MASK_ (0x0FFF0000)
+#define GPIO_CFG1_GPIOEN_(bit) BIT(16 + (bit))
+#define GPIO_CFG1_GPIOBUF_MASK_ (0x00000FFF)
+#define GPIO_CFG1_GPIOBUF_(bit) BIT(0 + (bit))
+
+#define GPIO_CFG2 (0x058)
+#define GPIO_CFG2_1588_POL_MASK_ (0x00000FFF)
+#define GPIO_CFG2_1588_POL_(bit) BIT(0 + (bit))
+
+#define GPIO_CFG3 (0x05C)
+#define GPIO_CFG3_1588_CH_SEL_MASK_ (0x0FFF0000)
+#define GPIO_CFG3_1588_CH_SEL_(bit) BIT(16 + (bit))
+#define GPIO_CFG3_1588_OE_MASK_ (0x00000FFF)
+#define GPIO_CFG3_1588_OE_(bit) BIT(0 + (bit))
+
+#define GPIO_WAKE (0x060)
+#define GPIO_WAKE_GPIOPOL_MASK_ (0x0FFF0000)
+#define GPIO_WAKE_GPIOPOL_(bit) BIT(16 + (bit))
+#define GPIO_WAKE_GPIOWK_MASK_ (0x00000FFF)
+#define GPIO_WAKE_GPIOWK_(bit) BIT(0 + (bit))
+
+#define GPIO_INT_STS (0x64)
+#define GPIO_INT_EN_SET (0x68)
+#define GPIO_INT_EN_CLR (0x6C)
+#define GPIO_INT_BIT_(bit) BIT(0 + (bit))
+
+#define FCT_INT_STS (0xA0)
+#define FCT_INT_EN_SET (0xA4)
+#define FCT_INT_EN_CLR (0xA8)
+#define FCT_INT_MASK_RDFPA_ (0xF0000000)
+#define FCT_INT_BIT_RDFPA_3_ BIT(31)
+#define FCT_INT_BIT_RDFPA_2_ BIT(30)
+#define FCT_INT_BIT_RDFPA_1_ BIT(29)
+#define FCT_INT_BIT_RDFPA_0_ BIT(28)
+#define FCT_INT_MASK_RDFO_ (0x0F000000)
+#define FCT_INT_BIT_RDFO_3_ BIT(27)
+#define FCT_INT_BIT_RDFO_2_ BIT(26)
+#define FCT_INT_BIT_RDFO_1_ BIT(25)
+#define FCT_INT_BIT_RDFO_0_ BIT(24)
+#define FCT_INT_MASK_RXDF_ (0x00F00000)
+#define FCT_INT_BIT_RXDF_3_ BIT(23)
+#define FCT_INT_BIT_RXDF_2_ BIT(22)
+#define FCT_INT_BIT_RXDF_1_ BIT(21)
+#define FCT_INT_BIT_RXDF_0_ BIT(20)
+#define FCT_INT_BIT_TXE_ BIT(16)
+#define FCT_INT_BIT_TDFO_ BIT(12)
+#define FCT_INT_BIT_TDFU_ BIT(8)
+#define FCT_INT_BIT_RX_DIS_3_ BIT(7)
+#define FCT_INT_BIT_RX_DIS_2_ BIT(6)
+#define FCT_INT_BIT_RX_DIS_1_ BIT(5)
+#define FCT_INT_BIT_RX_DIS_0_ BIT(4)
+#define FCT_INT_BIT_TX_DIS_ BIT(0)
+#define FCT_INT_MASK_ERRORS_ \
+ (FCT_INT_MASK_RDFO_ | \
+ FCT_INT_MASK_RXDF_ | \
+ FCT_INT_BIT_TXE_ | \
+ FCT_INT_BIT_TDFO_ | \
+ FCT_INT_BIT_TDFU_)
+
+#define FCT_RX_CTL (0xAC)
+#define FCT_RX_CTL_EN_(channel) BIT(28 + (channel))
+#define FCT_RX_CTL_DIS_(channel) BIT(24 + (channel))
+#define FCT_RX_CTL_RESET_(channel) BIT(20 + (channel))
+
+#define FCT_RX_FIFO_END (0xB0)
+#define FCT_RX_FIFO_END_3_ (0x3F000000)
+#define FCT_RX_FIFO_END_2_ (0x003F0000)
+#define FCT_RX_FIFO_END_1_ (0x00003F00)
+#define FCT_RX_FIFO_END_0_ (0x0000003F)
+
+#define FCT_RX_USED_0 (0xB4)
+#define FCT_RX_USED_1 (0xB8)
+#define FCT_RX_USED_2 (0xBC)
+#define FCT_RX_USED_3 (0xC0)
+#define FCT_RX_USED_MASK_ (0x0000FFFF)
+
+#define FCT_TX_CTL (0xC4)
+#define FCT_TX_CTL_EN_(channel) BIT(28 + (channel))
+#define FCT_TX_CTL_DIS_(channel) BIT(24 + (channel))
+#define FCT_TX_CTL_RESET_(channel) BIT(20 + (channel))
+
+#define FCT_TX_FIFO_END (0xC8)
+#define FCT_TX_FIFO_END_0_ (0x0000003F)
+
+#define FCT_TX_USED_0 (0xCC)
+#define FCT_TX_USED_0_MASK_ (0x0000FFFF)
+
+#define FCT_CFG (0xDC)
+#define FCT_CFG_ENABLE_OTHER_ROUTING_HEADERS_ BIT(4)
+#define FCT_CFG_STORE_BAD_FRAMES_ BIT(0)
+
+#define FCT_FLOW(rx_channel) (0xE0 + ((rx_channel) << 2))
+#define FCT_FLOW_CTL_OFF_THRESHOLD_ (0x00007F00)
+#define FCT_FLOW_CTL_OFF_THRESHOLD_SET_(value) \
+ ((value << 8) & FCT_FLOW_CTL_OFF_THRESHOLD_)
+#define FCT_FLOW_CTL_REQ_EN_ BIT(7)
+#define FCT_FLOW_CTL_ON_THRESHOLD_ (0x0000007F)
+#define FCT_FLOW_CTL_ON_THRESHOLD_SET_(value) \
+ ((value << 0) & FCT_FLOW_CTL_ON_THRESHOLD_)
+
+#define MAC_CR (0x100)
+#define MAC_CR_MII_EN_ BIT(19)
+#define MAC_CR_EEE_TX_CLK_STOP_EN_ BIT(18)
+#define MAC_CR_EEE_EN_ BIT(17)
+#define MAC_CR_EEE_TLAR_EN_ BIT(16)
+#define MAC_CR_ADP_ BIT(13)
+#define MAC_CR_ADD_ BIT(12)
+#define MAC_CR_ASD_ BIT(11)
+#define MAC_CR_INT_LOOP_ BIT(10)
+#define MAC_CR_BOLMT_MASK_ (0x000000C0)
+#define MAC_CR_CNTR_RST_ BIT(5)
+#define MAC_CR_CNTR_WEN_ BIT(4)
+#define MAC_CR_DPX_ BIT(3)
+#define MAC_CR_SPEED_MASK_ (0x00000006)
+#define MAC_CR_SPEED_1000_ (0x00000004)
+#define MAC_CR_SPEED_100_ (0x00000002)
+#define MAC_CR_SPEED_10_ (0x00000000)
+#define MAC_CR_RST_ BIT(0)
+
+#define MAC_RX (0x104)
+#define MAC_RX_MAX_SIZE_SHIFT_ (16)
+#define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000)
+#define MAC_RX_LEN_FLD_LT_CHK_ BIT(6)
+#define MAC_RX_WTL_ BIT(5)
+#define MAC_RX_FCS_STRIP_ BIT(4)
+#define MAC_RX_LFCD_ BIT(3)
+#define MAC_RX_VLAN_FSE_ BIT(2)
+#define MAC_RX_RXD_ BIT(1)
+#define MAC_RX_RXEN_ BIT(0)
+
+#define MAC_TX (0x108)
+#define MAC_TX_BAD_FCS_ BIT(2)
+#define MAC_TX_TXD_ BIT(1)
+#define MAC_TX_TXEN_ BIT(0)
+
+#define MAC_FLOW (0x10C)
+#define MAC_FLOW_CR_FORCE_FC_ BIT(31)
+#define MAC_FLOW_CR_TX_FCEN_ BIT(30)
+#define MAC_FLOW_CR_RX_FCEN_ BIT(29)
+#define MAC_FLOW_CR_FPF_ BIT(28)
+#define MAC_FLOW_CR_FCPT_MASK_ (0x0000FFFF)
+
+#define MAC_RAND_SEED (0x110)
+#define MAC_RAND_SEED_MASK_ (0x0000FFFF)
+
+#define MAC_ERR_STS (0x114)
+#define MAC_ERR_STS_RESERVED_ (0xFFFFF803)
+#define MAC_ERR_STS_LEN_ERR_ BIT(10)
+#define MAC_ERR_STS_RXERR_ BIT(9)
+#define MAC_ERR_STS_FERR_ BIT(8)
+#define MAC_ERR_STS_LFERR_ BIT(7)
+#define MAC_ERR_STS_RFERR_ BIT(6)
+#define MAC_ERR_STS_RWTERR_ BIT(5)
+#define MAC_ERR_STS_ECERR_ BIT(4)
+#define MAC_ERR_STS_ALERR_ BIT(3)
+#define MAC_ERR_STS_URERR_ BIT(2)
+
+#define MAC_RX_ADDRH (0x118)
+#define MAC_RX_ADDRH_MASK_ (0x0000FFFF)
+
+#define MAC_RX_ADDRL (0x11C)
+#define MAC_RX_ADDRL_MASK_ (0xFFFFFFFF)
+
+#define MAC_MII_ACC (0x120)
+#define MAC_MII_ACC_PHY_ADDR_SHIFT_ (11)
+#define MAC_MII_ACC_PHY_ADDR_MASK_ (0x0000F800)
+#define MAC_MII_ACC_MIIRINDA_SHIFT_ (6)
+#define MAC_MII_ACC_MIIRINDA_MASK_ (0x000007C0)
+#define MAC_MII_ACC_MII_READ_ (0x00000000)
+#define MAC_MII_ACC_MII_WRITE_ (0x00000002)
+#define MAC_MII_ACC_MII_BUSY_ BIT(0)
+
+#define MAC_MII_DATA (0x124)
+#define MAC_MII_DATA_MASK_ (0x0000FFFF)
+
+#define MAC_RGMII_ID (0x128)
+#define MAC_RGMII_ID_TXC_DELAY_EN_ BIT(1)
+#define MAC_RGMII_ID_RXC_DELAY_EN_ BIT(0)
+
+#define MAC_EEE_TX_LPI_REQ_DLY_CNT (0x130)
+#define MAC_EEE_TX_LPI_REQ_DLY_CNT_MASK_ (0xFFFFFFFF)
+
+#define MAC_EEE_TW_TX_SYS (0x134)
+#define MAC_EEE_TW_TX_SYS_CNT1G_MASK_ (0xFFFF0000)
+#define MAC_EEE_TW_TX_SYS_CNT100M_MASK_ (0x0000FFFF)
+
+#define MAC_EEE_TX_LPI_AUTO_REM_DLY (0x138)
+#define MAC_EEE_TX_LPI_AUTO_REM_DLY_CNT_ (0x00FFFFFF)
+
+#define MAC_WUCSR (0x140)
+#define MAC_WUCSR_TESTMODE_ BIT(31)
+#define MAC_WUCSR_IGNORE_WU_ BIT(20)
+#define MAC_WUCSR_IGNORE_WU_TIME_ (0x000F0000)
+#define MAC_WUCSR_DISCARD_FRAMES_D0A_ BIT(15)
+#define MAC_WUCSR_RFE_WAKE_EN_ BIT(14)
+#define MAC_WUCSR_EEE_TX_WAKE_ BIT(13)
+#define MAC_WUCSR_EEE_TX_WAKE_EN_ BIT(12)
+#define MAC_WUCSR_EEE_RX_WAKE_ BIT(11)
+#define MAC_WUCSR_EEE_RX_WAKE_EN_ BIT(10)
+#define MAC_WUCSR_RFE_WAKE_FR_ BIT(9)
+#define MAC_WUCSR_STORE_WAKE_ BIT(8)
+#define MAC_WUCSR_PFDA_FR_ BIT(7)
+#define MAC_WUCSR_WUFR_ BIT(6)
+#define MAC_WUCSR_MPR_ BIT(5)
+#define MAC_WUCSR_BCST_FR_ BIT(4)
+#define MAC_WUCSR_PFDA_EN_ BIT(3)
+#define MAC_WUCSR_WAKE_EN_ BIT(2)
+#define MAC_WUCSR_MPEN_ BIT(1)
+#define MAC_WUCSR_BCST_EN_ BIT(0)
+
+#define MAC_WK_SRC (0x144)
+#define MAC_WK_SRC_GPIOX_INT_WK_SHIFT_ (20)
+#define MAC_WK_SRC_GPIOX_INT_WK_MASK_ (0xFFF00000)
+#define MAC_WK_SRC_ETH_PHY_WK_ BIT(17)
+#define MAC_WK_SRC_IPV6_TCPSYN_RCD_WK_ BIT(16)
+#define MAC_WK_SRC_IPV4_TCPSYN_RCD_WK_ BIT(15)
+#define MAC_WK_SRC_EEE_TX_WK_ BIT(14)
+#define MAC_WK_SRC_EEE_RX_WK_ BIT(13)
+#define MAC_WK_SRC_RFE_FR_WK_ BIT(12)
+#define MAC_WK_SRC_PFDA_FR_WK_ BIT(11)
+#define MAC_WK_SRC_MP_FR_WK_ BIT(10)
+#define MAC_WK_SRC_BCAST_FR_WK_ BIT(9)
+#define MAC_WK_SRC_WU_FR_WK_ BIT(8)
+#define MAC_WK_SRC_WK_FR_SAVED_ BIT(7)
+#define MAC_WK_SRC_WK_FR_SAVE_RX_CH_ (0x00000060)
+#define MAC_WK_SRC_WUFF_MATCH_MASK_ (0x0000001F)
+
+#define MAC_WUF_CFG0 (0x150)
+#define MAC_NUM_OF_WUF_CFG (32)
+#define MAC_WUF_CFG_BEGIN (WUF_CFG0)
+#define MAC_WUF_CFG(index) (WUF_CFG_BEGIN + (4 * (index)))
+#define MAC_WUF_CFG_EN_ BIT(31)
+#define MAC_WUF_CFG_TYPE_MASK_ (0x03000000)
+#define MAC_WUF_CFG_TYPE_MCAST_ (0x02000000)
+#define MAC_WUF_CFG_TYPE_ALL_ (0x01000000)
+#define MAC_WUF_CFG_TYPE_UCAST_ (0x00000000)
+#define MAC_WUF_CFG_OFFSET_SHIFT_ (16)
+#define MAC_WUF_CFG_OFFSET_MASK_ (0x00FF0000)
+#define MAC_WUF_CFG_CRC16_MASK_ (0x0000FFFF)
+
+#define MAC_WUF_MASK0_0 (0x200)
+#define MAC_WUF_MASK0_1 (0x204)
+#define MAC_WUF_MASK0_2 (0x208)
+#define MAC_WUF_MASK0_3 (0x20C)
+#define MAC_NUM_OF_WUF_MASK (32)
+#define MAC_WUF_MASK0_BEGIN (MAC_WUF_MASK0_0)
+#define MAC_WUF_MASK1_BEGIN (MAC_WUF_MASK0_1)
+#define MAC_WUF_MASK2_BEGIN (MAC_WUF_MASK0_2)
+#define MAC_WUF_MASK3_BEGIN (MAC_WUF_MASK0_3)
+#define MAC_WUF_MASK0(index) (MAC_WUF_MASK0_BEGIN + (0x10 * (index)))
+#define MAC_WUF_MASK1(index) (MAC_WUF_MASK1_BEGIN + (0x10 * (index)))
+#define MAC_WUF_MASK2(index) (MAC_WUF_MASK2_BEGIN + (0x10 * (index)))
+#define MAC_WUF_MASK3(index) (MAC_WUF_MASK3_BEGIN + (0x10 * (index)))
+
+/* offset 0x400 - 0x500, x may range from 0 to 32, for a total of 33 entries */
+#define RFE_ADDR_FILT_HI(x) (0x400 + (8 * (x)))
+#define RFE_ADDR_FILT_HI_VALID_ BIT(31)
+#define RFE_ADDR_FILT_HI_TYPE_MASK_ (0x40000000)
+#define RFE_ADDR_FILT_HI_TYPE_SRC_ (0x40000000)
+#define RFE_ADDR_FILT_HI_TYPE_DST_ (0x00000000)
+#define RFE_ADDR_FILT_HI_PRI_FRM_ BIT(20)
+#define RFE_ADDR_FILT_HI_RSS_EN_ BIT(19)
+#define RFE_ADDR_FILT_HI_CH_EN_ BIT(18)
+#define RFE_ADDR_FILT_HI_CH_NUM_MASK_ (0x00030000)
+#define RFE_ADDR_FILT_HI_ADDR_MASK_ (0x0000FFFF)
+
+/* offset 0x404 - 0x504, x may range from 0 to 32, for a total of 33 entries */
+#define RFE_ADDR_FILT_LO(x) (0x404 + (8 * (x)))
+#define RFE_ADDR_FILT_LO_ADDR_MASK_ (0xFFFFFFFF)
+
+#define RFE_CTL (0x508)
+#define RFE_CTL_EN_OTHER_RT_HEADER_ BIT(18)
+#define RFE_CTL_DEFAULT_RX_CH_0_ (0x00000000)
+#define RFE_CTL_DEFAULT_RX_CH_1_ (0x00010000)
+#define RFE_CTL_DEFAULT_RX_CH_2_ (0x00020000)
+#define RFE_CTL_DEFAULT_RX_CH_3_ (0x00030000)
+#define RFE_CTL_DEFAULT_RX_CH_MASK_ (0x00030000)
+#define RFE_CTL_PASS_WKP_ BIT(15)
+#define RFE_CTL_IGMP_COE_ BIT(14)
+#define RFE_CTL_ICMP_COE_ BIT(13)
+#define RFE_CTL_TCPUDP_COE_ BIT(12)
+#define RFE_CTL_IP_COE_ BIT(11)
+#define RFE_CTL_AB_ BIT(10)
+#define RFE_CTL_AM_ BIT(9)
+#define RFE_CTL_AU_ BIT(8)
+#define RFE_CTL_VLAN_STRIP_ BIT(7)
+#define RFE_CTL_DISCARD_UNTAGGED_ BIT(6)
+#define RFE_CTL_VLAN_FILTER_ BIT(5)
+#define RFE_CTL_SA_FILTER_ BIT(4)
+#define RFE_CTL_MCAST_HASH_ BIT(3)
+#define RFE_CTL_DA_HASH_ BIT(2)
+#define RFE_CTL_DA_PERFECT_ BIT(1)
+#define RFE_CTL_RST_ BIT(0)
+
+#define RFE_PRI_SEL (0x50C)
+#define RFE_PRI_SEL_CH_NUM_PRI_7_ (0xC0000000)
+#define RFE_PRI_SEL_CH_NUM_PRI_6_ (0x30000000)
+#define RFE_PRI_SEL_CH_NUM_PRI_5_ (0x0C000000)
+#define RFE_PRI_SEL_CH_NUM_PRI_4_ (0x03000000)
+#define RFE_PRI_SEL_CH_NUM_PRI_3_ (0x00C00000)
+#define RFE_PRI_SEL_CH_NUM_PRI_2_ (0x00300000)
+#define RFE_PRI_SEL_CH_NUM_PRI_1_ (0x000C0000)
+#define RFE_PRI_SEL_CH_NUM_PRI_0_ (0x00030000)
+#define RFE_PRI_SEL_RSS_EN_PRI_7_ BIT(15)
+#define RFE_PRI_SEL_RSS_EN_PRI_6_ BIT(14)
+#define RFE_PRI_SEL_RSS_EN_PRI_5_ BIT(13)
+#define RFE_PRI_SEL_RSS_EN_PRI_4_ BIT(12)
+#define RFE_PRI_SEL_RSS_EN_PRI_3_ BIT(11)
+#define RFE_PRI_SEL_RSS_EN_PRI_2_ BIT(10)
+#define RFE_PRI_SEL_RSS_EN_PRI_1_ BIT(9)
+#define RFE_PRI_SEL_RSS_EN_PRI_0_ BIT(8)
+#define RFE_PRI_SEL_FM_PRI_EN_ BIT(7)
+#define RFE_PRI_SEL_FM_PRI_THRESH_ (0x00000070)
+#define RFE_PRI_SEL_USE_PRECEDENCE_ BIT(3)
+#define RFE_PRI_SEL_USE_IP_ BIT(2)
+#define RFE_PRI_SEL_USE_TAG_ BIT(1)
+#define RFE_PRI_SEL_VL_HIGHER_PRI_ BIT(0)
+
+#define RFE_DIFFSERV0 (0x510)
+#define RFE_DIFFSERV1 (0x514)
+#define RFE_DIFFSERV2 (0x518)
+#define RFE_DIFFSERV3 (0x51C)
+#define RFE_DIFFSERV4 (0x520)
+#define RFE_DIFFSERV5 (0x524)
+#define RFE_DIFFSERV6 (0x528)
+#define RFE_DIFFSERV7 (0x52C)
+
+#define RFE_RSS_CFG (0x554)
+#define RFE_RSS_CFG_UDP_IPV6_EX_ BIT(16)
+#define RFE_RSS_CFG_TCP_IPV6_EX_ BIT(15)
+#define RFE_RSS_CFG_IPV6_EX_ BIT(14)
+#define RFE_RSS_CFG_UDP_IPV6_ BIT(13)
+#define RFE_RSS_CFG_TCP_IPV6_ BIT(12)
+#define RFE_RSS_CFG_IPV6_ BIT(11)
+#define RFE_RSS_CFG_UDP_IPV4_ BIT(10)
+#define RFE_RSS_CFG_TCP_IPV4_ BIT(9)
+#define RFE_RSS_CFG_IPV4_ BIT(8)
+#define RFE_RSS_CFG_VALID_HASH_BITS_ (0x000000E0)
+#define RFE_RSS_CFG_RSS_QUEUE_ENABLE_ BIT(2)
+#define RFE_RSS_CFG_RSS_HASH_STORE_ BIT(1)
+#define RFE_RSS_CFG_RSS_ENABLE_ BIT(0)
+
+#define RFE_HASH_KEY0 (0x558)
+#define RFE_HASH_KEY1 (0x55C)
+#define RFE_HASH_KEY2 (0x560)
+#define RFE_HASH_KEY3 (0x564)
+#define RFE_HASH_KEY4 (0x568)
+#define RFE_HASH_KEY5 (0x56C)
+#define RFE_HASH_KEY6 (0x570)
+#define RFE_HASH_KEY7 (0x574)
+#define RFE_HASH_KEY8 (0x578)
+#define RFE_HASH_KEY9 (0x57C)
+
+#define MAC_WUCSR2 (0x600)
+#define MAC_WUCSR2_CSUM_DISABLE_ BIT(31)
+#define MAC_WUCSR2_EN_OTHER_RT_HDRS_ BIT(30)
+#define MAC_WUCSR2_FARP_FR_ BIT(10)
+#define MAC_WUCSR2_FNS_FR_ BIT(9)
+#define MAC_WUCSR2_NA_SA_SEL_ BIT(8)
+#define MAC_WUCSR2_NS_RCD_ BIT(7)
+#define MAC_WUCSR2_ARP_RCD_ BIT(6)
+#define MAC_WUCSR2_IPV6_TCPSYN_RCD_ BIT(5)
+#define MAC_WUCSR2_IPV4_TCPSYN_RCD_ BIT(4)
+#define MAC_WUCSR2_NS_OFFLOAD_EN_ BIT(3)
+#define MAC_WUCSR2_ARP_OFFLOAD_EN_ BIT(2)
+#define MAC_WUCSR2_IPV6_TCPSYN_WAKE_EN_ BIT(1)
+#define MAC_WUCSR2_IPV4_TCPSYN_WAKE_EN_ BIT(0)
+
+#define MAC_INT_STS (0x604)
+#define MAC_INT_EN_SET (0x608)
+#define MAC_INT_EN_CLR (0x60C)
+#define MAC_INT_BIT_EEE_START_TX_LPI_ BIT(26)
+#define MAC_INT_BIT_EEE_STOP_TX_LPI_ BIT(25)
+#define MAC_INT_BIT_EEE_RX_LPI_ BIT(24)
+#define MAC_INT_BIT_MACRTO_ BIT(23)
+#define MAC_INT_BIT_MAC_TX_DIS_ BIT(19)
+#define MAC_INT_BIT_MAC_RX_DIS_ BIT(18)
+#define MAC_INT_BIT_MAC_ERR_ BIT(15)
+#define MAC_INT_BIT_MAC_RX_CNT_ROLL_ BIT(14)
+#define MAC_INT_BIT_MAC_TX_CNT_ROLL_ BIT(13)
+
+#define INT_STS (0x780)
+#define INT_BIT_RESERVED_ (0xF0FEF000)
+#define INT_BIT_DMA_RX_(channel) BIT(24 + (channel))
+#define INT_BIT_ALL_RX_ (0x0F000000)
+#define INT_BIT_DMA_TX_(channel) BIT(16 + (channel))
+#define INT_BIT_ALL_TX_ (0x000F0000)
+#define INT_BIT_GPIO_ BIT(11)
+#define INT_BIT_DMA_GEN_ BIT(10)
+#define INT_BIT_SW_GP_ BIT(9)
+#define INT_BIT_PCIE_ BIT(8)
+#define INT_BIT_1588_ BIT(7)
+#define INT_BIT_OTP_RDY_ BIT(6)
+#define INT_BIT_PHY_ BIT(5)
+#define INT_BIT_DP_ BIT(4)
+#define INT_BIT_MAC_ BIT(3)
+#define INT_BIT_FCT_ BIT(2)
+#define INT_BIT_GPT_ BIT(1)
+#define INT_BIT_ALL_OTHER_ (0x00000FFE)
+#define INT_BIT_MAS_ BIT(0)
+
+#define INT_SET (0x784)
+
+#define INT_EN_SET (0x788)
+
+#define INT_EN_CLR (0x78C)
+
+#define INT_VEC_EN_SET (0x794)
+#define INT_VEC_EN_CLR (0x798)
+#define INT_VEC_EN_(vector_index) BIT(0 + vector_index)
+
+#define INT_VEC_MAP0 (0x7A0)
+#define INT_VMAP0_DMA_RX3_VEC_MASK_ (0x0000F000)
+#define INT_VMAP0_DMA_RX2_VEC_MASK_ (0x00000F00)
+#define INT_VMAP0_DMA_RX1_VEC_MASK_ (0x000000F0)
+#define INT_VMAP0_DMA_RX0_VEC_MASK_ (0x0000000F)
+
+#define INT_VEC_MAP1 (0x7A4)
+#define INT_VMAP1_DMA_TX0_VEC_MASK_ (0x0000000F)
+
+#define INT_VEC_MAP2 (0x7A8)
+#define INT_VMAP2_FCT_VEC_MASK_ (0x00F00000)
+#define INT_VMAP2_DMA_GEN_VEC_MASK_ (0x000F0000)
+#define INT_VMAP2_SW_GP_VEC_MASK_ (0x0000F000)
+#define INT_VMAP2_1588_VEC_MASK_ (0x00000F00)
+#define INT_VMAP2_GPT_VEC_MASK_ (0x000000F0)
+#define INT_VMAP2_OTHER_VEC_MASK_ (0x0000000F)
+
+#define INT_MOD_MAP0 (0x7B0)
+#define INT_MMAP0_DMA_RX3_MASK_ (0x0000F000)
+#define INT_MMAP0_DMA_RX2_MASK_ (0x00000F00)
+#define INT_MMAP0_DMA_RX1_MASK_ (0x000000F0)
+#define INT_MMAP0_DMA_RX0_MASK_ (0x0000000F)
+
+#define INT_MOD_MAP1 (0x7B4)
+#define INT_MMAP1_DMA_TX0_MASK_ (0x0000000F)
+
+#define INT_MOD_MAP2 (0x7B8)
+#define INT_MMAP2_FCT_MOD_MASK_ (0x00F00000)
+#define INT_MMAP2_DMA_GEN_MASK_ (0x000F0000)
+#define INT_MMAP2_SW_GP_MASK_ (0x0000F000)
+#define INT_MMAP2_1588_MASK_ (0x00000F00)
+#define INT_MMAP2_GPT_MASK_ (0x000000F0)
+#define INT_MMAP2_OTHER_MASK_ (0x0000000F)
+
+#define INT_MOD_CFG0 (0x7C0)
+#define INT_MOD_CFG1 (0x7C4)
+#define INT_MOD_CFG2 (0x7C8)
+#define INT_MOD_CFG3 (0x7CC)
+#define INT_MOD_CFG4 (0x7D0)
+#define INT_MOD_CFG5 (0x7D4)
+#define INT_MOD_CFG6 (0x7C8)
+#define INT_MOD_CFG7 (0x7DC)
+#define INT_MOD_CFG_STATUS_ BIT(18)
+#define INT_MOD_CFG_START_ BIT(17)
+#define INT_MOD_CFG_TMODE_MASK_ (0x00010000)
+#define INT_MOD_CFG_TMODE_ABS_ (0x00000000)
+#define INT_MOD_CFG_TMODE_CREDIT_ (0x00010000)
+#define INT_MOD_CFG_INTERVAL_MASK_ (0x00001FFF)
+
+#define PTP_CMD_CTL (0x0A00)
+#define PTP_CMD_CTL_PTP_CLOCK_TARGET_READ_ BIT(13)
+#define PTP_CMD_CTL_PTP_MANUAL_CAPTURE_SEL_MASK_ (0x00001E00)
+#define PTP_CMD_CTL_PTP_MANUAL_CAPTURE_ BIT(8)
+#define PTP_CMD_CTL_PTP_CLOCK_TEMP_RATE_ BIT(7)
+#define PTP_CMD_CTL_PTP_CLK_STP_NSEC_ BIT(6)
+#define PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_ BIT(5)
+#define PTP_CMD_CTL_PTP_CLOCK_LOAD_ BIT(4)
+#define PTP_CMD_CTL_PTP_CLOCK_READ_ BIT(3)
+#define PTP_CMD_CTL_PTP_ENABLE_ BIT(2)
+#define PTP_CMD_CTL_PTP_DISABLE_ BIT(1)
+#define PTP_CMD_CTL_PTP_RESET_ BIT(0)
+#define PTP_GENERAL_CONFIG (0x0A04)
+#define PTP_GENERAL_CONFIG_TSU_ENABLE_ BIT(31)
+#define PTP_GENERAL_CONFIG_GPIO_FECR_ BIT(25)
+#define PTP_GENERAL_CONFIG_GPIO_RECR_ BIT(24)
+#define PTP_GENERAL_CONFIG_GPIO_PTP_TIMER_INT_X_CLEAR_EN_(channel) \
+ (BIT(12 + ((channel) << 3)))
+#define PTP_GENERAL_CONFIG_GPIO_PTP_TIMER_INT_X_CLEAR_SEL_SET_(channel, value) \
+ (((value) & 0xF) << (8 + ((channel) << 3)))
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(channel) \
+ (0x7 << (1 + ((channel) << 2)))
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_100NS_ (0)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_10US_ (1)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_ (2)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_1MS_ (3)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_10MS_ (4)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_200MS_ (5)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_TOGGLE_ (6)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_INT_ (7)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_(channel, value) \
+ (((value) & 0x7) << (1 + ((channel) << 2)))
+#define PTP_GENERAL_CONFIG_RELOAD_ADD_X_(channel) (BIT((channel) << 2))
+
+#define PTP_INT_STS (0x0A08)
+#define PTP_INT_EN_SET (0x0A0C)
+#define PTP_INT_EN_CLR (0x0A10)
+#define PTP_INT_BIT_GPIO_FE(gpio_num) BIT(24 + (gpio_num))
+#define PTP_INT_BIT_GPIO_RE(gpio_num) BIT(16 + (gpio_num))
+#define PTP_INT_BIT_TX_SWTS_ERR_ BIT(13)
+#define PTP_INT_BIT_TX_TS_ BIT(12)
+#define PTP_INT_BIT_RX_TS_ BIT(8)
+#define PTP_INT_BIT_TIMER_B_ BIT(1)
+#define PTP_INT_BIT_TIMER_A_ BIT(0)
+#define PTP_INT_BIT_TIMER_(channel) BIT(channel)
+
+#define PTP_CLOCK_SEC (0x0A14)
+#define PTP_CLOCK_NS (0x0A18)
+#define PTP_CLOCK_SUBNS (0x0A1C)
+#define PTP_CLOCK_RATE_ADJ (0x0A20)
+#define PTP_CLOCK_RATE_ADJ_DIR_ BIT(31)
+#define PTP_CLOCK_RATE_ADJ_VALUE_MASK_ (0x3FFFFFFF)
+#define PTP_CLOCK_TEMP_RATE_ADJ (0x0A24)
+#define PTP_CLOCK_TEMP_RATE_DURATION (0x0A28)
+#define PTP_CLOCK_STEP_ADJ (0x0A2C)
+#define PTP_CLOCK_STEP_ADJ_DIR_ BIT(31)
+#define PTP_CLOCK_STEP_ADJ_VALUE_MASK_ (0x3FFFFFFF)
+#define PTP_CLOCK_TARGET_SEC_X(channel) (0x0A30 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_NS_X(channel) (0x0A34 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_RELOAD_SEC_X(channel) (0x0A38 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_RELOAD_NS_X(channel) (0x0A3C + ((channel) << 4))
+#define PTP_USER_MAC_HI (0x0A50)
+#define PTP_USER_MAC_LO (0x0A54)
+#define PTP_GPIO_SEL (0x0A58)
+#define PTP_LATENCY (0x0A5C)
+#define PTP_CAP_INFO (0x0A60)
+#define PTP_CAP_INFO_TX_TS_CNT_GET_(reg_val) ((reg_val & 0x00000070) >> 4)
+#define PTP_RX_PARSE_CONFIG (0x0A64)
+#define PTP_RX_TIMESTAMP_CONFIG (0x0A68)
+
+#define PTP_RX_INGRESS_SEC (0x0A78)
+#define PTP_RX_INGRESS_NS (0x0A7C)
+#define PTP_RX_MSG_HEADER (0x0A80)
+#define PTP_TX_PARSE_CONFIG (0x0A9C)
+#define PTP_TX_TIMESTAMP_CONFIG (0x0AA0)
+#define PTP_TX_MOD (0x0AA4)
+#define PTP_TX_MOD2 (0x0AA8)
+#define PTP_TX_EGRESS_SEC (0x0AAC)
+#define PTP_TX_EGRESS_NS (0x0AB0)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_ (0xC0000000)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_ (0x00000000)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_ (0x40000000)
+#define PTP_TX_EGRESS_NS_TS_NS_MASK_ (0x3FFFFFFF)
+#define PTP_TX_MSG_HEADER (0x0AB4)
+#define PTP_TX_ONE_STEP_SYNC_SEC (0x0AC0)
+#define PTP_GPIO_CAP_CONFIG (0x0AC4)
+#define PTP_GPIO_RE_CLOCK_SEC_CAP (0x0AC8)
+#define PTP_GPIO_RE_CLOCK_NS_CAP (0x0ACC)
+#define PTP_GPIO_FE_CLOCK_SEC_CAP (0x0AD0)
+#define PTP_GPIO_FE_CLOCK_NS_CAP (0x0AD4)
+
+#define DMAC_CFG (0xC00)
+#define DMAC_CFG_INTR_DSCR_RD_EN_ BIT(18)
+#define DMAC_CFG_INTR_DSCR_WR_EN_ BIT(17)
+#define DMAC_CFG_COAL_EN_ BIT(16)
+#define DMAC_CFG_CMPL_RETRY_CNT_MASK_ (0x00006000)
+#define DMAC_CFG_CMPL_RETRY_EN_ BIT(12)
+#define DMAC_CFG_CH_ARB_SEL_MASK_ (0x00000C00)
+#define DMAC_CFG_CH_ARB_SEL_RX_HIGH_ (0x00000000)
+#define DMAC_CFG_CH_ARB_SEL_CH_ORDER_ BIT(10)
+#define DMAC_CFG_CH_ARB_SEL_RX_HIGH_RR_ BIT(11)
+#define DMAC_CFG_CH_ARB_SEL_RR_ (0x00000C00)
+#define DMAC_CFG_MAX_READ_REQ_MASK_ (0x00000070)
+#define DMAC_CFG_MAX_READ_REQ_SET_(val) \
+ ((((u32)(val)) << 4) & DMAC_CFG_MAX_READ_REQ_MASK_)
+#define DMAC_CFG_MAX_DSPACE_MASK_ (0x00000003)
+#define DMAC_CFG_MAX_DSPACE_16_ (0x00000000)
+#define DMAC_CFG_MAX_DSPACE_32_ (0x00000001)
+#define DMAC_CFG_MAX_DSPACE_64_ BIT(1)
+#define DMAC_CFG_MAX_DSPACE_128_ (0x00000003)
+
+#define DMAC_COAL_CFG (0xC04)
+#define DMAC_COAL_CFG_TIMER_LIMIT_MASK_ (0xFFF00000)
+#define DMAC_COAL_CFG_FLUSH_INTS_ BIT(18)
+#define DMAC_COAL_CFG_INT_EXIT_COAL_ BIT(17)
+#define DMAC_COAL_CFG_CSR_EXIT_COAL_ BIT(16)
+#define DMAC_COAL_CFG_TX_THRES_MASK_ (0x0000FF00)
+#define DMAC_COAL_CFG_RX_THRES_MASK_ (0x000000FF)
+
+#define DMAC_OBFF_CFG (0xC08)
+#define DMAC_OBFF_TX_THRES_MASK_ (0x0000FF00)
+#define DMAC_OBFF_RX_THRES_MASK_ (0x000000FF)
+
+#define DMAC_CMD (0xC0C)
+#define DMAC_CMD_SWR_ BIT(31)
+#define DMAC_CMD_COAL_EXIT_ BIT(28)
+#define DMAC_CMD_TX_SWR_(channel) BIT(24 + (channel))
+#define DMAC_CMD_START_T_(channel) BIT(20 + (channel))
+#define DMAC_CMD_STOP_T_(channel) BIT(16 + (channel))
+#define DMAC_CMD_RX_SWR_(channel) BIT(8 + (channel))
+#define DMAC_CMD_START_R_(channel) BIT(4 + (channel))
+#define DMAC_CMD_STOP_R_(channel) BIT(0 + (channel))
+
+#define DMAC_INT_STS (0xC10)
+#define DMAC_INT_EN_SET (0xC14)
+#define DMAC_INT_EN_CLR (0xC18)
+#define DMAC_INT_BIT_RXPRI_(channel) BIT(24 + (channel))
+#define DMAC_INT_BIT_ERR_ BIT(21)
+#define DMAC_INT_BIT_RXFRM_(channel) BIT(16 + (channel))
+#define DMAC_INT_BIT_RX_STOP_(channel) BIT(12 + (channel))
+#define DMAC_INT_BIT_TX_STOP_(channel) BIT(8 + (channel))
+#define DMAC_INT_BIT_TX_IOC_(channel) BIT(0 + (channel))
+
+#define DMAC_RX_ABS_TIMER_CFG (0xC1C)
+#define DMAC_RX_ABS_TIMER_CFG_SHARE_MASK_ (0x00F00000)
+#define DMAC_RX_ABS_TIMER_CFG_SHARE_3_ BIT(23)
+#define DMAC_RX_ABS_TIMER_CFG_SHARE_2_ BIT(22)
+#define DMAC_RX_ABS_TIMER_CFG_SHARE_1_ BIT(21)
+#define DMAC_RX_ABS_TIMER_CFG_SHARE_0_ BIT(20)
+#define DMAC_RX_ABS_TIMER_CFG_WR_ BIT(19)
+#define DMAC_RX_ABS_TIMER_CFG_SEL_MASK_ (0x00070000)
+#define DMAC_RX_ABS_TIMER_CFG_CNT_MASK_ (0x0000FFFF)
+
+#define DMAC_RX_TIMER_CFG (0xC20)
+#define DMAC_RX_TIMER_CFG_TMR_MODE_MASK_ (0x1F000000)
+#define DMAC_RX_TIMER_CFG_TMR_SHARED_FRAME_MODE_ BIT(28)
+#define DMAC_RX_TIMER_CFG_TMR_TIMER3_FRAME_MODE_ BIT(27)
+#define DMAC_RX_TIMER_CFG_TMR_TIMER2_FRAME_MODE_ BIT(26)
+#define DMAC_RX_TIMER_CFG_TMR_TIMER1_FRAME_MODE_ BIT(25)
+#define DMAC_RX_TIMER_CFG_TMR_TIMER0_FRAME_MODE_ BIT(24)
+#define DMAC_RX_TIMER_CFG_SHARE_MAP_MASK_ (0x00F00000)
+#define DMAC_RX_TIMER_CFG_SHARE_MAP_TIMER3_ BIT(23)
+#define DMAC_RX_TIMER_CFG_SHARE_MAP_TIMER2_ BIT(22)
+#define DMAC_RX_TIMER_CFG_SHARE_MAP_TIMER1_ BIT(21)
+#define DMAC_RX_TIMER_CFG_SHARE_MAP_TIMER0_ BIT(20)
+#define DMAC_RX_TIMER_CFG_WR_ BIT(19)
+#define DMAC_RX_TIMER_CFG_CH_SEL_MASK_ (0x00070000)
+#define DMAC_RX_TIMER_CFG_CH_SEL_TIMER0_ (0x00000000)
+#define DMAC_RX_TIMER_CFG_CH_SEL_TIMER1_ (0x00010000)
+#define DMAC_RX_TIMER_CFG_CH_SEL_TIMER2_ (0x00020000)
+#define DMAC_RX_TIMER_CFG_CH_SEL_TIMER3_ (0x00030000)
+#define DMAC_RX_TIMER_CFG_CH_SEL_SHARED_ (0x00040000)
+#define DMAC_RX_TIMER_CFG_CNT_MASK_ (0x0000FFFF)
+
+#define DMAC_TXTMR_CFG (0xC24)
+#define DMAC_TXTMR_CFG_TX_DELAY_WR_ BIT(23)
+#define DMAC_TXTMR_CFG_TX_DELAY_CNT_ (0x0000FFFF)
+
+#define DMAC_TX_ABSTMR_CFG (0xC28)
+#define DMAC_TX_ABSTMR_WR_ BIT(23)
+#define DMAC_TX_ABSTMR_CNT_ (0x0000FFFF)
+
+#define RX_CFG_A(channel) (0xC40 + ((channel) << 6))
+#define RX_CFG_A_RX_WB_SWFLUSH_ BIT(31)
+#define RX_CFG_A_RX_WB_ON_INT_TMR_ BIT(30)
+#define RX_CFG_A_RX_WB_THRES_MASK_ (0x1F000000)
+#define RX_CFG_A_RX_PF_THRES_MASK_ (0x001F0000)
+#define RX_CFG_A_RX_PF_PRI_THRES_MASK_ (0x00001F00)
+#define RX_CFG_A_RX_HP_WB_EN_ BIT(5)
+#define RX_CFG_A_RX_HP_WB_THRES_MASK_ (0x0000000F)
+
+#define RX_CFG_B(channel) (0xC44 + ((channel) << 6))
+#define RX_CFG_B_TS_ALL_RX_ BIT(29)
+#define RX_CFG_B_TS_DECR_EN_ BIT(28)
+#define RX_CFG_B_RX_PAD_MASK_ (0x03000000)
+#define RX_CFG_B_RX_PAD_0_ (0x00000000)
+#define RX_CFG_B_RX_PAD_2_ (0x02000000)
+#define RX_CFG_B_RX_COAL_DIS_ BIT(23)
+#define RX_CFG_B_RX_DESCR_RO_EN_ BIT(21)
+#define RX_CFG_B_RX_DATA_RO_EN_ BIT(20)
+#define RX_CFG_B_RDMABL_MASK_ (0x00070000)
+#define RX_CFG_B_RDMABL_32_ (0x00000000)
+#define RX_CFG_B_RDMABL_64_ (0x00010000)
+#define RX_CFG_B_RDMABL_128_ (0x00020000)
+#define RX_CFG_B_RDMABL_256_ (0x00030000)
+#define RX_CFG_B_RDMABL_512_ (0x00040000)
+#define RX_CFG_B_RDMABL_1024_ (0x00050000)
+#define RX_CFG_B_RDMABL_2048_ (0x00060000)
+#define RX_CFG_B_RDMABL_4096_ (0x00070000)
+#define RX_CFG_B_RX_RING_LEN_MASK_ (0x0000FFFF)
+
+#define RX_BASE_ADDRH(channel) (0xC48 + ((channel) << 6))
+#define RX_BASE_ADDRH_MASK_ (0xFFFFFFFF)
+
+#define RX_BASE_ADDRL(channel) (0xC4C + ((channel) << 6))
+#define RX_BASE_ADDRL_MASK_ (0xFFFFFFFC)
+
+#define RX_HEAD_WRITEBACK_ADDRH(channel) (0xC50 + ((channel) << 6))
+
+#define RX_HEAD_WRITEBACK_ADDRL(channel) (0xC54 + ((channel) << 6))
+
+#define RX_HEAD(channel) (0xC58 + ((channel) << 6))
+#define RX_HEAD_MASK_ (0x0000FFFF)
+
+#define RX_TAIL(channel) (0xC5C + ((channel) << 6))
+#define RX_TAIL_MASK_ (0x0000FFFF)
+
+#define DMAC_RX_ERR_STS(channel) (0xC60 + ((channel) << 6))
+#define DMAC_RX_ERR_STS_RESERVED_ (0xFFDFFF9F)
+#define DMAC_RX_ERR_STS_RX_DESC_TAIL_ERR_EN_ BIT(21)
+#define DMAC_RX_ERR_STS_RX_DESC_READ_ERR_ BIT(6)
+#define DMAC_RX_ERR_STS_RX_DESC_TAIL_ERR_ BIT(5)
+
+#define TX_CFG_A(channel) (0xD40 + ((channel) << 6))
+#define TX_CFG_A_TX_HP_WB_SWFLUSH_ BIT(31)
+#define TX_CFG_A_TX_HP_WB_ON_INT_TMR_ BIT(30)
+#define TX_CFG_A_TX_TMR_HPWB_SEL_MASK_ (0x30000000)
+#define TX_CFG_A_TX_TMR_HPWB_SEL_DIS_ (0x00000000)
+#define TX_CFG_A_TX_TMR_HPWB_SEL_IOC_ (0x10000000)
+#define TX_CFG_A_TX_TMR_HPWB_SEL_LS_ (0x20000000)
+#define TX_CFG_A_TX_TMR_HPWB_SEL_IOC_LS_ (0x30000000)
+#define TX_CFG_A_TX_PF_THRES_MASK_ (0x001F0000)
+#define TX_CFG_A_TX_PF_PRI_THRES_MASK_ (0x00001F00)
+#define TX_CFG_A_TX_STOP_TXE_ BIT(7)
+#define TX_CFG_A_TX_HP_WB_EN_ BIT(5)
+#define TX_CFG_A_TX_HP_WB_ON_TXTMR_ BIT(4)
+#define TX_CFG_A_TX_HP_WB_THRES_MASK_ (0x0000000F)
+
+#define TX_CFG_B(channel) (0xD44 + ((channel) << 6))
+#define TX_CFG_B_TX_COAL_DIS_ BIT(23)
+#define TX_CFG_B_TX_DESC_RO_EN_ BIT(22)
+#define TX_CFG_B_TX_DATA_RO_EN_ BIT(21)
+#define TX_CFG_B_TX_HEAD_RO_EN_ BIT(20)
+#define TX_CFG_B_TDMABL_MASK_ (0x00070000)
+#define TX_CFG_B_TDMABL_32_ (0x00000000)
+#define TX_CFG_B_TDMABL_64_ (0x00010000)
+#define TX_CFG_B_TDMABL_128_ (0x00020000)
+#define TX_CFG_B_TDMABL_256_ (0x00030000)
+#define TX_CFG_B_TDMABL_512_ (0x00040000)
+#define TX_CFG_B_TX_RING_LEN_MASK_ (0x0000FFFF)
+
+#define TX_BASE_ADDRH(channel) (0xD48 + ((channel) << 6))
+#define TX_BASE_ADDRH_MASK_ (0xFFFFFFFF)
+
+#define TX_BASE_ADDRL(channel) (0xD4C + ((channel) << 6))
+#define TX_BASE_ADDRL_MASK_ (0xFFFFFFFC)
+
+#define TX_HEAD_WRITEBACK_ADDRH(channel) (0xD50 + ((channel) << 6))
+#define TX_HEAD_WRITEBACK_ADDRH_MASK_ (0xFFFFFFFF)
+
+#define TX_HEAD_WRITEBACK_ADDRL(channel) (0xD54 + ((channel) << 6))
+#define TX_HEAD_WRITEBACK_ADDRL_MASK_ (0xFFFFFFFC)
+
+#define TX_HEAD(channel) (0xD58 + ((channel) << 6))
+#define TX_HEAD_MASK_ (0x0000FFFF)
+
+#define TX_TAIL(channel) (0xD5C + ((channel) << 6))
+#define TX_TAIL_MASK_ (0x0000FFFF)
+
+#define DMAC_TX_ERR_STS(channel) (0xD60 + ((channel) << 6))
+#define DMAC_TX_ERR_STS_RESERVED_ (0xFFDEFF00)
+#define DMAC_TX_ERR_STS_TX_DESC_TAIL_ERR_EN_ BIT(21)
+#define DMAC_TX_ERR_STS_TX_DESC_SEQ_ERR_EN_ BIT(16)
+#define DMAC_TX_ERR_STS_TX_DATA_READ_ERR_ BIT(7)
+#define DMAC_TX_ERR_STS_TX_DESC_READ_ERR_ BIT(6)
+#define DMAC_TX_ERR_STS_TX_DESC_TAIL_ERR_ BIT(5)
+#define DMAC_TX_ERR_STS_TX_FCT_TXE_ BIT(4)
+#define DMAC_TX_ERR_STS_TX_DESC_DATATYPE_ERR_ BIT(3)
+#define DMAC_TX_ERR_STS_TX_DESC_EXTNTYPE_ERR_ BIT(2)
+#define DMAC_TX_ERR_STS_TX_DESC_EXTRAFS_ERR_ BIT(1)
+#define DMAC_TX_ERR_STS_TX_DESC_NOFS_ERR_ BIT(0)
+
+#define DMAC_DEBUG_0 (0xFF0)
+#define DMAC_DEBUG_1 (0xFF4)
+#define DMAC_DEBUG_2 (0xFF8)
+
+/* MAC statistics registers */
+#define STAT_RX_FCS_ERRORS (0x1200)
+#define STAT_RX_ALIGNMENT_ERRORS (0x1204)
+#define STAT_RX_FRAGMENT_ERRORS (0x1208)
+#define STAT_RX_JABBER_ERRORS (0x120C)
+#define STAT_RX_UNDERSIZE_FRAME_ERRORS (0x1210)
+#define STAT_RX_OVERSIZE_FRAME_ERRORS (0x1214)
+#define STAT_RX_DROPPED_FRAMES (0x1218)
+#define STAT_RX_UNICAST_BYTE_COUNT (0x121C)
+#define STAT_RX_BROADCAST_BYTE_COUNT (0x1220)
+#define STAT_RX_MULTICAST_BYTE_COUNT (0x1224)
+#define STAT_RX_UNICAST_FRAMES (0x1228)
+#define STAT_RX_BROADCAST_FRAMES (0x122C)
+#define STAT_RX_MULTICAST_FRAMES (0x1230)
+#define STAT_RX_PAUSE_FRAMES (0x1234)
+#define STAT_RX_64_BYTE_FRAMES (0x1238)
+#define STAT_RX_65_127_BYTE_FRAMES (0x123C)
+#define STAT_RX_128_255_BYTE_FRAMES (0x1240)
+#define STAT_RX_256_511_BYTES_FRAMES (0x1244)
+#define STAT_RX_512_1023_BYTE_FRAMES (0x1248)
+#define STAT_RX_1024_1518_BYTE_FRAMES (0x124C)
+#define STAT_RX_GREATER_1518_BYTE_FRAMES (0x1250)
+#define STAT_RX_TOTAL_FRAMES (0x1254)
+#define STAT_EEE_RX_LPI_TRANSITIONS (0x1258)
+#define STAT_EEE_RX_LPI_TIME (0x125C)
+#define STAT_RX_COUNTER_ROLLOVER_STATUS (0x127C)
+
+#define STAT_TX_FCS_ERRORS (0x1280)
+#define STAT_TX_EXCESS_DEFERRAL_ERRORS (0x1284)
+#define STAT_TX_CARRIER_ERRORS (0x1288)
+#define STAT_TX_BAD_BYTE_COUNT (0x128C)
+#define STAT_TX_SINGLE_COLLISIONS (0x1290)
+#define STAT_TX_MULTIPLE_COLLISIONS (0x1294)
+#define STAT_TX_EXCESSIVE_COLLISION (0x1298)
+#define STAT_TX_LATE_COLLISIONS (0x129C)
+#define STAT_TX_UNICAST_BYTE_COUNT (0x12A0)
+#define STAT_TX_BROADCAST_BYTE_COUNT (0x12A4)
+#define STAT_TX_MULTICAST_BYTE_COUNT (0x12A8)
+#define STAT_TX_UNICAST_FRAMES (0x12AC)
+#define STAT_TX_BROADCAST_FRAMES (0x12B0)
+#define STAT_TX_MULTICAST_FRAMES (0x12B4)
+#define STAT_TX_PAUSE_FRAMES (0x12B8)
+#define STAT_TX_64_BYTE_FRAMES (0x12BC)
+#define STAT_TX_65_127_BYTE_FRAMES (0x12C0)
+#define STAT_TX_128_255_BYTE_FRAMES (0x12C4)
+#define STAT_TX_256_511_BYTES_FRAMES (0x12C8)
+#define STAT_TX_512_1023_BYTE_FRAMES (0x12CC)
+#define STAT_TX_1024_1518_BYTE_FRAMES (0x12D0)
+#define STAT_TX_GREATER_1518_BYTE_FRAMES (0x12D4)
+#define STAT_TX_TOTAL_FRAMES (0x12D8)
+#define STAT_EEE_TX_LPI_TRANSITIONS (0x12DC)
+#define STAT_EEE_TX_LPI_TIME (0x12E0)
+#define STAT_TX_COUNTER_ROLLOVER_STATUS (0x12FC)
+
+/* End of Register definitions */
+
+#define LAN743X_NUMBER_OF_TX_CHANNELS (1)
+#define LAN743X_NUMBER_OF_RX_CHANNELS (4)
+#define LAN743X_PHY_TRACE_ENABLE (0)
+struct lan743x_adapter;
+
+#define NETIF_INFO(adapter, type, netdev, fmt, ...) \
+ netif_info(adapter, type, netdev, "%s.INFO: " fmt "\n", \
+ __func__, ##__VA_ARGS__)
+#define NETIF_WARNING(adapter, type, netdev, fmt, ...) \
+ netif_warn(adapter, type, netdev, "%s.WARNING: " fmt "\n", \
+ __func__, ##__VA_ARGS__)
+#define NETIF_ERROR(adapter, type, netdev, fmt, ...) \
+ netif_err(adapter, type, netdev, "%s.ERROR: " fmt "\n", \
+ __func__, ##__VA_ARGS__)
+#define NETIF_ASSERT(adapter, type, netdev, condition) \
+ do { if (!(condition)) netif_err(adapter, type, netdev, \
+ "ASSERTION_FAILURE, File = %s, Line = %d\n", \
+ __FILE__, __LINE__); } while (0)
+
+/* PCI */
+/* SMSC acquired EFAR late 1990's, MCHP acquired SMSC 2012 */
+#define PCI_VENDOR_ID_SMSC PCI_VENDOR_ID_EFAR
+#define PCI_DEVICE_ID_SMSC_LAN7430 (0x7430)
+
+#define PCI_CONFIG_LENGTH (0x1000)
+
+struct lan743x_pci {
+ struct pci_dev *pdev;
+ int init_flags;
+ unsigned long bar_flags;
+};
+
+static int lan743x_pci_init(struct lan743x_adapter *adapter,
+ struct pci_dev *pdev);
+static void lan743x_pci_cleanup(struct lan743x_adapter *adapter);
+static u8 __iomem *lan743x_pci_get_bar_address(struct lan743x_adapter *adapter,
+ int bar);
+static void lan743x_pci_release_bar_address(struct lan743x_adapter *adapter,
+ int bar, u8 __iomem *bar_address);
+static unsigned int lan743x_pci_get_irq(struct lan743x_adapter *adapter);
+
+/* CSR */
+#define CSR_LENGTH (0x2000)
+
+struct lan743x_csr {
+ u8 __iomem *csr_address;
+ u32 id_rev;
+ u32 fpga_rev;
+};
+
+static int lan743x_csr_init(struct lan743x_adapter *adapter);
+static void lan743x_csr_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_csr_light_reset(struct lan743x_adapter *adapter);
+static inline u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset);
+static inline void lan743x_csr_write(struct lan743x_adapter *adapter,
+ int offset, u32 data);
+
+/* INTERRUPTS */
+typedef void(*lan743x_vector_handler)(void *context, u32 int_sts);
+
+struct lan743x_vector {
+ struct lan743x_adapter *adapter;
+ int vector_index;
+ int irq;
+ u32 int_mask;
+ lan743x_vector_handler handler;
+ void *context;
+};
+
+#define LAN743X_MAX_VECTOR_COUNT (6)
+
+struct lan743x_intr {
+ int flags;
+
+ unsigned int irq;
+
+ struct msix_entry msix_entries[LAN743X_MAX_VECTOR_COUNT];
+
+ struct lan743x_vector vector_list[LAN743X_MAX_VECTOR_COUNT];
+ int number_of_vectors;
+
+ int software_isr_flag;
+};
+
+static void lan743x_vector_init(struct lan743x_vector *vector,
+ struct lan743x_adapter *adapter,
+ int vector_index, int irq, u32 int_mask,
+ lan743x_vector_handler handler, void *context);
+
+static int lan743x_intr_init(struct lan743x_adapter *adapter);
+static void lan743x_intr_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_intr_open(struct lan743x_adapter *adapter);
+static void lan743x_intr_close(struct lan743x_adapter *adapter);
+
+/* DP */
+struct lan743x_dp {
+ int flags;
+
+ /* lock, used to prevent concurrent access to data port */
+ struct mutex lock;
+};
+
+static int lan743x_dp_init(struct lan743x_adapter *adapter);
+static void lan743x_dp_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_dp_open(struct lan743x_adapter *adapter);
+static void lan743x_dp_close(struct lan743x_adapter *adapter);
+
+static int lan743x_dp_write_hash_filter(
+ struct lan743x_adapter *adapter,
+ u32 *hash_data);
+
+/* GPIO */
+struct lan743x_gpio {
+ /* gpio_lock: used to prevent concurrent access to gpio settings */
+ spinlock_t gpio_lock;
+
+ int used_bits;
+ int output_bits;
+ int ptp_bits;
+ u32 gpio_cfg0;
+ u32 gpio_cfg1;
+ u32 gpio_cfg2;
+ u32 gpio_cfg3;
+};
+
+static int lan743x_gpio_init(struct lan743x_adapter *adapter);
+static void lan743x_gpio_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_gpio_open(struct lan743x_adapter *adapter);
+static void lan743x_gpio_close(struct lan743x_adapter *adapter);
+
+/* PTP */
+#include "linux/ptp_clock_kernel.h"
+
+#define LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS (4)
+
+#define PTP_FLAG_PTP_CLOCK_REGISTERED BIT(1)
+#define PTP_FLAG_ISR_ENABLED BIT(2)
+
+struct lan743x_ptp {
+ int flags;
+
+ /* command_lock: used to prevent concurrent ptp commands */
+ struct mutex command_lock;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_clock_info;
+ struct ptp_pin_desc pin_config[1];
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+ struct tasklet_struct ptp_isr_bottom_half;
+
+#define LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS (2)
+ unsigned long used_event_ch;
+
+ int pps_event_ch;
+ int pps_gpio_bit;
+
+ /* tx_ts_lock: used to prevent concurrent access to timestamp arrays */
+ struct mutex tx_ts_lock;
+ int pending_tx_timestamps;
+ struct sk_buff *tx_ts_skb_queue[
+ LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+ int tx_ts_skb_queue_size;
+ u32 tx_ts_seconds_queue[
+ LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+ u32 tx_ts_nseconds_queue[
+ LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+ int tx_ts_queue_size;
+};
+
+static void lan743x_ptp_isr(void *context);
+
+static int lan743x_ptp_init(struct lan743x_adapter *adapter);
+static void lan743x_ptp_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_ptp_open(struct lan743x_adapter *adapter);
+static void lan743x_ptp_close(struct lan743x_adapter *adapter);
+
+static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter);
+static void lan743x_ptp_enable(struct lan743x_adapter *adapter);
+static void lan743x_ptp_disable(struct lan743x_adapter *adapter);
+static void lan743x_ptp_reset(struct lan743x_adapter *adapter);
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
+ u32 *seconds, u32 *nano_seconds,
+ u32 *sub_nano_seconds);
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
+ u32 seconds, u32 nano_seconds,
+ u32 sub_nano_seconds);
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
+ s64 time_step_ns);
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+static bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter);
+static void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter,
+ struct sk_buff *skb);
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_get_clock_index(struct lan743x_adapter *adapter);
+#endif
+
+/* MAC */
+struct lan743x_mac {
+ int flags;
+
+ struct mii_bus *mdiobus;
+ /* mii_mutex: used to prevent concurrent access to mdiobus */
+ struct mutex mii_mutex;
+
+ u8 mac_address[ETH_ALEN];
+
+ /* tx_mutext: used to prevent concurrent access to tx_enable_bits */
+ struct mutex tx_mutex;
+ unsigned long tx_enable_bits;
+
+ /* rx_mutex: used to prevent concurrent access to rx_enable_bits */
+ struct mutex rx_mutex;
+ unsigned long rx_enable_bits;
+
+ struct net_device_stats statistics;
+};
+
+#define LAN743X_MAX_FRAME_SIZE (9 * 1024)
+
+static void lan743x_mac_isr(void *context);
+
+static int lan743x_mac_init(struct lan743x_adapter *adapter);
+static void lan743x_mac_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_mac_open(struct lan743x_adapter *adapter);
+static void lan743x_mac_close(struct lan743x_adapter *adapter);
+
+static void lan743x_mac_get_address(struct lan743x_adapter *adapter,
+ u8 *mac_addr);
+
+static int lan743x_mac_mii_read(struct lan743x_adapter *adapter,
+ int phy_id, int index);
+static int lan743x_mac_mii_write(struct lan743x_adapter *adapter,
+ int phy_id, int index, u16 regval);
+
+static void lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter,
+ bool tx_enable, bool rx_enable);
+
+static int lan743x_mac_tx_enable(struct lan743x_adapter *adapter,
+ int tx_channel);
+static int lan743x_mac_tx_disable(struct lan743x_adapter *adapter,
+ int tx_channel);
+static int lan743x_mac_rx_enable(struct lan743x_adapter *adapter,
+ int rx_channel);
+static int lan743x_mac_rx_disable(struct lan743x_adapter *adapter,
+ int rx_channel);
+static int lan743x_mac_set_mtu(struct lan743x_adapter *adapter, int new_mtu);
+
+static struct net_device_stats *mac_get_stats(struct lan743x_adapter *adapter);
+
+/* PHY */
+struct lan743x_phy {
+ int flags;
+
+ bool fc_autoneg;
+ u8 fc_request_control;
+};
+
+static int lan743x_phy_init(struct lan743x_adapter *adapter);
+static void lan743x_phy_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_phy_open(struct lan743x_adapter *adapter);
+static void lan743x_phy_close(struct lan743x_adapter *adapter);
+
+/* RFE */
+struct lan743x_rfe {
+ int flags;
+};
+
+static int lan743x_rfe_init(struct lan743x_adapter *adapter);
+static void lan743x_rfe_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_rfe_open(struct lan743x_adapter *adapter);
+static void lan743x_rfe_close(struct lan743x_adapter *adapter);
+
+static void lan743x_rfe_set_multicast(struct lan743x_adapter *adapter);
+
+/* FCT */
+
+static void lan743x_fct_isr(void *context);
+
+static int lan743x_fct_init(struct lan743x_adapter *adapter);
+static void lan743x_fct_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_fct_open(struct lan743x_adapter *adapter);
+static void lan743x_fct_close(struct lan743x_adapter *adapter);
+
+static int lan743x_fct_rx_reset(struct lan743x_adapter *adapter,
+ int rx_channel);
+static int lan743x_fct_rx_enable(struct lan743x_adapter *adapter,
+ int rx_channel);
+static int lan743x_fct_rx_disable(struct lan743x_adapter *adapter,
+ int rx_channel);
+
+static int lan743x_fct_tx_reset(struct lan743x_adapter *adapter,
+ int tx_channel);
+static int lan743x_fct_tx_enable(struct lan743x_adapter *adapter,
+ int tx_channel);
+static int lan743x_fct_tx_disable(struct lan743x_adapter *adapter,
+ int tx_channel);
+
+/* DMAC */
+struct lan743x_dmac {
+ int flags;
+
+ int descriptor_spacing;
+};
+
+static void lan743x_dmac_isr(void *context);
+
+static int lan743x_dmac_init(struct lan743x_adapter *adapter);
+static void lan743x_dmac_cleanup(struct lan743x_adapter *adapter);
+static int lan743x_dmac_open(struct lan743x_adapter *adapter);
+static void lan743x_dmac_close(struct lan743x_adapter *adapter);
+
+static int lan743x_dmac_get_descriptor_spacing(struct lan743x_adapter *adapter);
+
+static int lan743x_dmac_reserve_tx_channel(struct lan743x_adapter *adapter,
+ int tx_channel);
+static void lan743x_dmac_release_tx_channel(struct lan743x_adapter *adapter,
+ int tx_channel);
+static int lan743x_dmac_reserve_rx_channel(struct lan743x_adapter *adapter,
+ int rx_channel);
+static void lan743x_dmac_release_rx_channel(struct lan743x_adapter *adapter,
+ int rx_channel);
+static int lan743x_dmac_tx_reset(struct lan743x_adapter *adapter,
+ int tx_channel);
+static int lan743x_dmac_tx_start(struct lan743x_adapter *adapter,
+ int tx_channel);
+static int lan743x_dmac_tx_stop(struct lan743x_adapter *adapter,
+ int tx_channel);
+static int lan743x_dmac_rx_reset(struct lan743x_adapter *adapter,
+ int rx_channel);
+static int lan743x_dmac_rx_start(struct lan743x_adapter *adapter,
+ int rx_channel);
+static int lan743x_dmac_rx_stop(struct lan743x_adapter *adapter,
+ int rx_channel);
+
+/* TX */
+struct lan743x_tx_descriptor;
+struct lan743x_tx_buffer_info;
+
+#define TX_FLAG_MAC_ENABLED BIT(1)
+#define TX_FLAG_FIFO_ENABLED BIT(2)
+#define TX_FLAG_ISR_ENABLED BIT(3)
+#define TX_FLAG_DMAC_STARTED BIT(4)
+#define TX_FLAG_GPIO0_RESERVED BIT(5)
+#define TX_FLAG_GPIO1_RESERVED BIT(6)
+#define TX_FLAG_GPIO2_RESERVED BIT(7)
+#define TX_FLAG_GPIO3_RESERVED BIT(8)
+#define TX_FLAG_TIMESTAMPING_ENABLED BIT(9)
+#define TX_FLAG_RING_ALLOCATED BIT(10)
+
+#define GPIO_QUEUE_STARTED (0)
+#define GPIO_TX_FUNCTION (1)
+#define GPIO_TX_COMPLETION (2)
+#define GPIO_TX_FRAGMENT (3)
+
+#define TX_FRAME_FLAG_IN_PROGRESS BIT(0)
+
+struct lan743x_tx {
+ struct lan743x_adapter *adapter;
+ int flags;
+ int channel_number;
+
+ int ring_size;
+ size_t ring_allocation_size;
+ struct lan743x_tx_descriptor *ring_cpu_ptr;
+ dma_addr_t ring_dma_ptr;
+ /* ring_lock: used to prevent concurrent access to tx ring */
+ spinlock_t ring_lock;
+ u32 frame_flags;
+ u32 frame_first;
+ u32 frame_data0;
+ u32 frame_tail;
+
+ struct lan743x_tx_buffer_info *buffer_info;
+
+ u32 *head_cpu_ptr;
+ dma_addr_t head_dma_ptr;
+ int last_head;
+ int last_tail;
+
+ struct tasklet_struct tx_isr_bottom_half;
+
+ struct sk_buff *overflow_skb;
+};
+
+static void lan743x_tx_isr(void *context, u32 int_sts);
+
+static int lan743x_tx_ring_init(struct lan743x_tx *tx);
+static void lan743x_tx_ring_cleanup(struct lan743x_tx *tx);
+static int lan743x_tx_init(struct lan743x_tx *tx,
+ struct lan743x_adapter *adapter,
+ int channel_number);
+static void lan743x_tx_cleanup(struct lan743x_tx *tx);
+static int lan743x_tx_open(struct lan743x_tx *tx);
+static void lan743x_tx_close(struct lan743x_tx *tx);
+
+static void lan743x_tx_set_timestamping_enable(struct lan743x_tx *tx,
+ bool enabled);
+
+static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
+ struct sk_buff *skb);
+
+/* RX */
+struct lan743x_rx_descriptor;
+struct lan743x_rx_buffer_info;
+
+#define RX_FLAG_NAPI_ADDED BIT(0)
+#define RX_FLAG_DMAC_STARTED BIT(1)
+#define RX_FLAG_ISR_ENABLED BIT(2)
+#define RX_FLAG_FIFO_ENABLED BIT(3)
+#define RX_FLAG_MAC_ENABLED BIT(4)
+#define RX_FLAG_RING_ALLOCATED BIT(5)
+
+struct lan743x_rx {
+ struct lan743x_adapter *adapter;
+ int flags;
+ int channel_number;
+
+ int ring_size;
+ size_t ring_allocation_size;
+ struct lan743x_rx_descriptor *ring_cpu_ptr;
+ dma_addr_t ring_dma_ptr;
+
+ struct lan743x_rx_buffer_info *buffer_info;
+
+ u32 *head_cpu_ptr;
+ dma_addr_t head_dma_ptr;
+ u32 last_head;
+
+ struct napi_struct napi;
+};
+
+static void lan743x_rx_isr(void *context, u32 int_sts);
+
+static int lan743x_rx_ring_init(struct lan743x_rx *rx);
+static void lan743x_rx_ring_cleanup(struct lan743x_rx *rx);
+static int lan743x_rx_init(struct lan743x_rx *rx,
+ struct lan743x_adapter *adapter, int channel_number);
+static void lan743x_rx_cleanup(struct lan743x_rx *rx);
+static int lan743x_rx_open(struct lan743x_rx *rx);
+static void lan743x_rx_close(struct lan743x_rx *rx);
+
+struct lan743x_adapter {
+ struct net_device *netdev;
+ int init_flags;
+ int open_flags;
+
+ int msg_enable;
+
+ struct lan743x_pci pci;
+ struct lan743x_csr csr;
+ struct lan743x_intr intr;
+ struct lan743x_dp dp;
+ struct lan743x_gpio gpio;
+ struct lan743x_ptp ptp;
+ struct lan743x_mac mac;
+ struct lan743x_phy phy;
+ struct lan743x_rfe rfe;
+ struct lan743x_dmac dmac;
+ struct lan743x_tx tx[LAN743X_NUMBER_OF_TX_CHANNELS];
+ struct lan743x_rx rx[LAN743X_NUMBER_OF_RX_CHANNELS];
+};
+
+#endif /* _LAN743X_H */
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 0/3] Add LAN743X driver
From: Bryan.Whitehead @ 2017-08-11 19:47 UTC (permalink / raw)
To: netdev, davem; +Cc: UNGLinuxDriver
From: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Add Microchip LAN743X PCIe 3.1 Gigabit Ethernet Controller Driver
Bryan Whitehead (3):
Add LAN743X driver
Add LAN743X to Kconfig and Makefile
Add LAN743X to MAINTAINER list
MAINTAINERS | 7 +
drivers/net/ethernet/microchip/Kconfig | 10 +-
drivers/net/ethernet/microchip/Makefile | 1 +
drivers/net/ethernet/microchip/lan743x.c | 6842 ++++++++++++++++++++++++++++++
drivers/net/ethernet/microchip/lan743x.h | 1417 +++++++
5 files changed, 8276 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/microchip/lan743x.c
create mode 100644 drivers/net/ethernet/microchip/lan743x.h
--
2.7.4
^ permalink raw reply
* Re: [PATCH][next] Bluetooth: kfree tmp rather than an alias to it
From: Marcel Holtmann @ 2017-08-11 19:20 UTC (permalink / raw)
To: Colin King
Cc: Gustavo F. Padovan, Johan Hedberg, David S. Miller,
open list:BLUETOOTH DRIVERS, Netdev list, kernel-janitors,
linux-kernel
In-Reply-To: <20170811183304.17580-1-colin.king@canonical.com>
Hi Colin,
> While the kfree of dhkey_a is of the same address of tmp, it
> probably is clearer and more human readable if tmp is kfree'd
> rather than dhkey_a.
>
> Detected by CoverityScan, CID#1448650 ("Free of address-of expression")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
> net/bluetooth/selftest.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
patch has been applied to bluetooth-next tree.
Regards
Marcel
^ permalink raw reply
* Re: BUG_ON(sg->sg_magic != SG_MAGIC) on tls socket.
From: Dave Watson @ 2017-08-11 19:15 UTC (permalink / raw)
To: Dave Jones, Ilya Lesokhin, Aviad Yehezkel; +Cc: netdev
In-Reply-To: <20170811185201.7afmkfa3cuoqm4u2@codemonkey.org.uk>
Hi Dave,
On 08/11/17 02:52 PM, Dave Jones wrote:
> kernel BUG at ./include/linux/scatterlist.h:189!
> invalid opcode: 0000 [#1] SMP KASAN
...
> Call Trace:
> ? copy_page_to_iter+0x6c0/0x6c0
> tls_sw_sendmsg+0x6d8/0x9c0
> ? alloc_sg+0x510/0x510
> ? cyc2ns_read_end+0x10/0x10
> ? import_iovec+0xa8/0x1f0
> ? do_syscall_64+0x1bc/0x3e0
> ? entry_SYSCALL64_slow_path+0x25/0x25
> inet_sendmsg+0xce/0x310
...
> 186 static inline void sg_mark_end(struct scatterlist *sg)
> 187 {
> 188 #ifdef CONFIG_DEBUG_SG
> 189 BUG_ON(sg->sg_magic != SG_MAGIC);
> 190 #endif
+added mellanox folks
I haven't seen this one yet. The specific sequence of
sendmsg/sendpage calls would probably be super helpful to nail it down
Thanks
^ permalink raw reply
* BUG_ON(sg->sg_magic != SG_MAGIC) on tls socket.
From: Dave Jones @ 2017-08-11 18:52 UTC (permalink / raw)
To: netdev; +Cc: davejwatson
kernel BUG at ./include/linux/scatterlist.h:189!
invalid opcode: 0000 [#1] SMP KASAN
CPU: 3 PID: 20890 Comm: trinity-c51 Not tainted 4.13.0-rc4-think+ #5
task: ffff88036e3d1cc0 task.stack: ffff88033e9d8000
RIP: 0010:tls_push_record+0x675/0x680
RSP: 0018:ffff88033e9df630 EFLAGS: 00010287
RAX: 0000000000000000 RBX: ffff8802ee3b8968 RCX: ffffffff82226754
RDX: dffffc0000000000 RSI: dffffc0000000000 RDI: ffff8802ee3b8c10
RBP: ffff88033e9df6d0 R08: 0000000000000000 R09: ffffed005d107004
R10: 0000000000000004 R11: ffffed005d107003 R12: ffff880341b30668
R13: ffff8802ee3b8c10 R14: ffff8802ee3b8c38 R15: 0000000087654321
FS: 00007f465ced2700(0000) GS:ffff88046b600000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000029cbf021f8 CR3: 000000045abd0000 CR4: 00000000001406e0
DR0: 00007f8f17bd2000 DR1: 00007f8c27d0f000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000600
Call Trace:
? copy_page_to_iter+0x6c0/0x6c0
tls_sw_sendmsg+0x6d8/0x9c0
? alloc_sg+0x510/0x510
? cyc2ns_read_end+0x10/0x10
? import_iovec+0xa8/0x1f0
? do_syscall_64+0x1bc/0x3e0
? entry_SYSCALL64_slow_path+0x25/0x25
inet_sendmsg+0xce/0x310
? inet_recvmsg+0x3a0/0x3a0
? inet_recvmsg+0x3a0/0x3a0
sock_write_iter+0x1b0/0x280
? kernel_sendmsg+0x70/0x70
? __might_sleep+0x72/0xe0
do_iter_readv_writev+0x29a/0x370
? vfs_dedupe_file_range+0x3f0/0x3f0
? rw_verify_area+0x65/0x150
do_iter_write+0xd7/0x2a0
? __hrtimer_run_queues+0x980/0x980
vfs_writev+0x142/0x220
? __fget_light+0x1ae/0x230
? vfs_iter_write+0x70/0x70
? syscall_exit_register+0x3f0/0x3f0
? rcutorture_record_progress+0x20/0x20
? __fdget_pos+0x88/0x120
? __fdget_raw+0x20/0x20
do_writev+0xd2/0x1c0
? do_writev+0xd2/0x1c0
? vfs_writev+0x220/0x220
? mark_held_locks+0x23/0xb0
? do_syscall_64+0xc0/0x3e0
? SyS_readv+0x20/0x20
SyS_writev+0x10/0x20
do_syscall_64+0x1bc/0x3e0
? syscall_return_slowpath+0x240/0x240
? __context_tracking_exit.part.5+0x23d/0x2a0
? cpumask_check.part.2+0x10/0x10
? mark_held_locks+0x23/0xb0
? return_from_SYSCALL_64+0x2d/0x7a
? trace_hardirqs_on_caller+0x182/0x260
? trace_hardirqs_on_thunk+0x1a/0x1c
entry_SYSCALL64_slow_path+0x25/0x25
RIP: 0033:0x7f465c7fd219
RSP: 002b:00007ffda332a238 EFLAGS: 00000246
ORIG_RAX: 0000000000000014
RAX: ffffffffffffffda RBX: 0000000000000014 RCX: 00007f465c7fd219
RDX: 0000000000000047 RSI: 00000029cbef1b50 RDI: 0000000000000137
RBP: 00007ffda332a2e0 R08: 0000000000000100 R09: fffffffffffffff8
R10: 000000000000fff9 R11: 0000000000000246 R12: 0000000000000002
R13: 00007f465cd66058 R14: 00007f465ced2698 R15: 00007f465cd66000
Code: 8d bb 58 04 00 00 e8 3b d5 20 ff 48 8b 83 58 04 00 00 f0 80 48 08 04 48 83 c4 78 44 89 f0 5b 41 5c 41 5d 41 5e 41 5f 5d c3 0f 0b <0f> 0b 0f 0b 0f 0b 0f 1f 44 00 00 0f 1f 44 00 00 55 ba 17 00 00
RIP: tls_push_record+0x675/0x680 RSP: ffff88033e9df630
186 static inline void sg_mark_end(struct scatterlist *sg)
187 {
188 #ifdef CONFIG_DEBUG_SG
189 BUG_ON(sg->sg_magic != SG_MAGIC);
190 #endif
^ permalink raw reply
* [PATCH][next] Bluetooth: kfree tmp rather than an alias to it
From: Colin King @ 2017-08-11 18:33 UTC (permalink / raw)
To: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, David S . Miller,
linux-bluetooth, netdev
Cc: kernel-janitors, linux-kernel
From: Colin Ian King <colin.king@canonical.com>
While the kfree of dhkey_a is of the same address of tmp, it
probably is clearer and more human readable if tmp is kfree'd
rather than dhkey_a.
Detected by CoverityScan, CID#1448650 ("Free of address-of expression")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
net/bluetooth/selftest.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/selftest.c b/net/bluetooth/selftest.c
index ee92c925ecc5..34a1227f4391 100644
--- a/net/bluetooth/selftest.c
+++ b/net/bluetooth/selftest.c
@@ -164,7 +164,7 @@ static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32],
ret = -EINVAL;
out:
- kfree(dhkey_a);
+ kfree(tmp);
return ret;
}
--
2.11.0
^ permalink raw reply related
* [PATCH net-next] liquidio: moved ptp_enable to octeon_device structure
From: Felix Manlunas @ 2017-08-11 18:22 UTC (permalink / raw)
To: davem
Cc: netdev, raghu.vatsavayi, derek.chickles, satananda.burla,
intiyaz.basha
From: Intiyaz Basha <intiyaz.basha@cavium.com>
ptp_enable was a global static variable. Moved this global variable to
octeon_device structure and removed extra device id check.
Signed-off-by: Intiyaz Basha <intiyaz.basha@cavium.com>
Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
---
drivers/net/ethernet/cavium/liquidio/lio_main.c | 19 ++++++++++---------
drivers/net/ethernet/cavium/liquidio/octeon_device.h | 1 +
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index cbd6287..8bf6dfc 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -78,8 +78,6 @@ int octeon_console_debug_enabled(u32 console)
return (console_bitmask >> (console)) & 0x1;
}
-static int ptp_enable = 1;
-
/* Polling interval for determining when NIC application is alive */
#define LIQUIDIO_STARTER_POLL_INTERVAL_MS 100
@@ -1363,6 +1361,13 @@ liquidio_probe(struct pci_dev *pdev,
if (pdev->device == OCTEON_CN23XX_PF_VID)
oct_dev->msix_on = LIO_FLAG_MSIX_ENABLED;
+ /* Enable PTP for 6XXX Device */
+ if (((pdev->device == OCTEON_CN66XX) ||
+ (pdev->device == OCTEON_CN68XX)))
+ oct_dev->ptp_enable = true;
+ else
+ oct_dev->ptp_enable = false;
+
dev_info(&pdev->dev, "Initializing device %x:%x.\n",
(u32)pdev->vendor, (u32)pdev->device);
@@ -2388,9 +2393,7 @@ liquidio_push_packet(u32 octeon_id __attribute__((unused)),
r_dh_off = (rh->r_dh.len - 1) * BYTES_PER_DHLEN_UNIT;
- if (((oct->chip_id == OCTEON_CN66XX) ||
- (oct->chip_id == OCTEON_CN68XX)) &&
- ptp_enable) {
+ if (oct->ptp_enable) {
if (rh->r_dh.has_hwtstamp) {
/* timestamp is included from the hardware at
* the beginning of the packet.
@@ -2735,8 +2738,7 @@ static int liquidio_open(struct net_device *netdev)
oct->droq[0]->ops.poll_mode = 1;
}
- if ((oct->chip_id == OCTEON_CN66XX || oct->chip_id == OCTEON_CN68XX) &&
- ptp_enable)
+ if (oct->ptp_enable)
oct_ptp_open(netdev);
ifstate_set(lio, LIO_IFSTATE_RUNNING);
@@ -3091,8 +3093,7 @@ static int liquidio_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
switch (cmd) {
case SIOCSHWTSTAMP:
- if ((lio->oct_dev->chip_id == OCTEON_CN66XX ||
- lio->oct_dev->chip_id == OCTEON_CN68XX) && ptp_enable)
+ if (lio->oct_dev->ptp_enable)
return hwtstamp_ioctl(netdev, ifr);
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
index 31efdef..b014e6a 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h
@@ -554,6 +554,7 @@ struct octeon_device {
} loc;
atomic_t *adapter_refcount; /* reference count of adapter */
+ bool ptp_enable;
};
#define OCT_DRV_ONLINE 1
^ permalink raw reply related
* [PATCH v2] netfilter: nf_nat_h323: fix logical-not-parentheses warning
From: Nick Desaulniers @ 2017-08-11 18:16 UTC (permalink / raw)
To: pablo
Cc: mka, lorenzo, Nick Desaulniers, Jozsef Kadlecsik,
Florian Westphal, David S. Miller, Alexey Kuznetsov,
Hideaki YOSHIFUJI, netfilter-devel, coreteam, netdev,
linux-kernel
In-Reply-To: <20170811174259.GA3743@salvia>
Clang produces the following warning:
net/ipv4/netfilter/nf_nat_h323.c:553:6: error:
logical not is only applied to the left hand side of this comparison
[-Werror,-Wlogical-not-parentheses]
if (!set_h225_addr(skb, protoff, data, dataoff, taddr,
^
add parentheses after the '!' to evaluate the comparison first
add parentheses around left hand side expression to silence this warning
There's not necessarily a bug here, but it's cleaner to return early,
ex:
if (x)
return
...
rather than:
if (!x == 0)
...
else
return
Also added a return code check that seemed to be missing in one
instance.
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
---
Changes in v2:
* Reorder if/else blocks to return early.
* Also handle this for set_h245_addr(), not just set_h225_addr().
* Add return code check for the Gnomemeeting case.
net/ipv4/netfilter/nf_nat_h323.c | 57 +++++++++++++++++++++-------------------
1 file changed, 30 insertions(+), 27 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 574f7ebba0b6..ac8342dcb55e 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -252,16 +252,16 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
if (set_h245_addr(skb, protoff, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons((port & htons(1)) ? nated_port + 1 :
- nated_port)) == 0) {
- /* Save ports */
- info->rtp_port[i][dir] = rtp_port;
- info->rtp_port[i][!dir] = htons(nated_port);
- } else {
+ nated_port))) {
nf_ct_unexpect_related(rtp_exp);
nf_ct_unexpect_related(rtcp_exp);
return -1;
}
+ /* Save ports */
+ info->rtp_port[i][dir] = rtp_port;
+ info->rtp_port[i][!dir] = htons(nated_port);
+
/* Success */
pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n",
&rtp_exp->tuple.src.u3.ip,
@@ -370,15 +370,15 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
/* Modify signal */
if (set_h225_addr(skb, protoff, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
- htons(nated_port)) == 0) {
- /* Save ports */
- info->sig_port[dir] = port;
- info->sig_port[!dir] = htons(nated_port);
- } else {
+ htons(nated_port))) {
nf_ct_unexpect_related(exp);
return -1;
}
+ /* Save ports */
+ info->sig_port[dir] = port;
+ info->sig_port[!dir] = htons(nated_port);
+
pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n",
&exp->tuple.src.u3.ip,
ntohs(exp->tuple.src.u.tcp.port),
@@ -462,24 +462,27 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
/* Modify signal */
if (set_h225_addr(skb, protoff, data, 0, &taddr[idx],
&ct->tuplehash[!dir].tuple.dst.u3,
- htons(nated_port)) == 0) {
- /* Save ports */
- info->sig_port[dir] = port;
- info->sig_port[!dir] = htons(nated_port);
-
- /* Fix for Gnomemeeting */
- if (idx > 0 &&
- get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
- (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
- set_h225_addr(skb, protoff, data, 0, &taddr[0],
- &ct->tuplehash[!dir].tuple.dst.u3,
- info->sig_port[!dir]);
- }
- } else {
+ htons(nated_port))) {
nf_ct_unexpect_related(exp);
return -1;
}
+ /* Save ports */
+ info->sig_port[dir] = port;
+ info->sig_port[!dir] = htons(nated_port);
+
+ /* Fix for Gnomemeeting */
+ if (idx > 0 &&
+ get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
+ (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
+ if (set_h225_addr(skb, protoff, data, 0, &taddr[0],
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ info->sig_port[!dir])) {
+ nf_ct_unexpect_related(exp);
+ return -1;
+ }
+ }
+
/* Success */
pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n",
&exp->tuple.src.u3.ip,
@@ -550,9 +553,9 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
}
/* Modify signal */
- if (!set_h225_addr(skb, protoff, data, dataoff, taddr,
- &ct->tuplehash[!dir].tuple.dst.u3,
- htons(nated_port)) == 0) {
+ if (set_h225_addr(skb, protoff, data, dataoff, taddr,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ htons(nated_port))) {
nf_ct_unexpect_related(exp);
return -1;
}
--
2.14.0.434.g98096fd7a8-goog
^ permalink raw reply related
* Re: Some traffic stress testing with 4.13.0-rc4-next-20170808 and BUG: [61183.212237] BUG: Bad page state in process ksoftirqd/52 pfn:855f2f
From: Cong Wang @ 2017-08-11 18:08 UTC (permalink / raw)
To: Paweł Staszewski; +Cc: Linux Kernel Network Developers, intel-wired-lan
In-Reply-To: <bcffda88-02ab-8d17-bdef-97cf39c409ee@itcare.pl>
(Cc'ing Intel)
On Thu, Aug 10, 2017 at 3:05 AM, Paweł Staszewski <pstaszewski@itcare.pl> wrote:
> Hi
>
>
> yes there are some stack traces more
>
> enp24s0f3 - this NIC is used only for ssh to the host (not much traffic on
> it)
>
> enp216s0f1 - this NIC was have 6Mpps TX traffic (when stack trace occured)
>
> enp216s0f0 - this NIC was have 6Mpps RX traffic (when stack trace occured)
>
>
> - complete dmesg with stack traces for all nics below:
There are several warnings, the first one is igb driver related, the second one
is RCU related.
The first BUG is likely an ixgbe driver issue.
>
> [53838.303348] NETDEV WATCHDOG: enp24s0f3 (igb): transmit queue 1 timed out
> [53838.303358] ------------[ cut here ]------------
> [53838.303363] WARNING: CPU: 0 PID: 8 at net/sched/sch_generic.c:316
> dev_watchdog+0xc5/0x122
> [53838.303363] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
> [53838.303367] CPU: 0 PID: 8 Comm: ksoftirqd/0 Not tainted
> 4.13.0-rc4-next-20170808 #1
> [53838.303368] task: ffff88046da39400 task.stack: ffffc900001b8000
> [53838.303369] RIP: 0010:dev_watchdog+0xc5/0x122
> [53838.303369] RSP: 0018:ffffc900001bbda0 EFLAGS: 00010286
> [53838.303370] RAX: 000000000000003c RBX: ffff88046beb6000 RCX:
> 0000000000000000
> [53838.303371] RDX: ffff88046fa13310 RSI: ffff88046fa0ca98 RDI:
> ffff88046fa0ca98
> [53838.303371] RBP: ffffc900001bbdb0 R08: 0000000000000000 R09:
> 0000000000000000
> [53838.303372] R10: ffff88046fa188e0 R11: ffff88087ff94a84 R12:
> 0000000000000001
> [53838.303372] R13: ffffffff815e0007 R14: ffff88046beb6438 R15:
> ffff88046beb6000
> [53838.303373] FS: 0000000000000000(0000) GS:ffff88046fa00000(0000)
> knlGS:0000000000000000
> [53838.303374] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [53838.303374] CR2: 00007ffc18047d58 CR3: 000000046c51f003 CR4:
> 00000000007606f0
> [53838.303375] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> [53838.303375] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> 0000000000000400
> [53838.303376] PKRU: 55555554
> [53838.303376] Call Trace:
> [53838.303381] call_timer_fn+0x5b/0x123
> [53838.303382] run_timer_softirq+0x137/0x15a
> [53838.303386] ? pick_next_task_fair+0x139/0x2f9
> [53838.303388] __do_softirq+0xe4/0x23a
> [53838.303390] ? sort_range+0x1d/0x1d
> [53838.303391] run_ksoftirqd+0x15/0x2a
> [53838.303392] smpboot_thread_fn+0x128/0x13f
> [53838.303394] kthread+0xf7/0xfc
> [53838.303395] ? init_completion+0x24/0x24
> [53838.303399] ret_from_fork+0x22/0x30
> [53838.303400] Code: 62 68 6e 00 00 75 38 48 89 df c6 05 56 68 6e 00 01 e8
> f4 49 fe ff 44 89 e1 48 89 de 48 c7 c7 5b 3d ac 81 48 89 c2 e8 c8 26 a9 ff
> <0f> ff eb 10 41 ff c4 48 05 40 01 00 00 41 39 f4 75 9a eb 0d 48
> [53838.303417] ---[ end trace cf42df41100f38ce ]---
> [53838.303555] igb 0000:18:00.3 enp24s0f3: Reset adapter
> [53843.119595] igb 0000:18:00.3 enp24s0f3: igb: enp24s0f3 NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX
> [56238.303636] igb 0000:18:00.3 enp24s0f3: Reset adapter
> [56241.651735] igb 0000:18:00.3 enp24s0f3: igb: enp24s0f3 NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX
> [59482.865823] nr_pdflush_threads exported in /proc is scheduled for removal
> [59697.280051] ------------[ cut here ]------------
> [59697.280060] WARNING: CPU: 45 PID: 237 at kernel/rcu/tree.c:2700
> rcu_process_callbacks+0x327/0x36f
> [59697.280061] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
> [59697.280066] CPU: 45 PID: 237 Comm: ksoftirqd/45 Tainted: G W
> 4.13.0-rc4-next-20170808 #1
> [59697.280067] task: ffff88086d07a800 task.stack: ffffc90003bd4000
> [59697.280069] RIP: 0010:rcu_process_callbacks+0x327/0x36f
> [59697.280070] RSP: 0018:ffffc90003bd7e00 EFLAGS: 00010097
> [59697.280071] RAX: 0000000000000246 RBX: ffff88087fa598c0 RCX:
> ffffffffffffd800
> [59697.280071] RDX: 0000000000000001 RSI: ffffc90003bd7e18 RDI:
> ffff88087fa598f8
> [59697.280072] RBP: ffffc90003bd7e60 R08: 0000000000000068 R09:
> 00000000ffffff80
> [59697.280073] R10: ffffc90003bd7dd8 R11: 000000000001cc80 R12:
> ffffffff81c423c0
> [59697.280073] R13: ffffc90003bd7e18 R14: ffff88087fa598f8 R15:
> ffff88086d07a800
> [59697.280074] FS: 0000000000000000(0000) GS:ffff88087fa40000(0000)
> knlGS:0000000000000000
> [59697.280075] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [59697.280075] CR2: 00007fffd1a54000 CR3: 000000086bc53001 CR4:
> 00000000007606e0
> [59697.280076] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> [59697.280077] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> 0000000000000400
> [59697.280077] PKRU: 55555554
> [59697.280078] Call Trace:
> [59697.280081] ? net_rx_action+0x21e/0x22d
> [59697.280084] __do_softirq+0xe4/0x23a
> [59697.280088] ? sort_range+0x1d/0x1d
> [59697.280089] run_ksoftirqd+0x15/0x2a
> [59697.280090] smpboot_thread_fn+0x128/0x13f
> [59697.280093] kthread+0xf7/0xfc
> [59697.280094] ? init_completion+0x24/0x24
> [59697.280099] ret_from_fork+0x22/0x30
> [59697.280100] Code: 8b 8b 90 00 00 00 48 2b 0d 2b 4e bc 00 48 39 ca 7d 07
> 48 89 93 90 00 00 00 48 83 7b 38 00 0f 94 c1 48 85 d2 0f 94 c2 38 d1 74 02
> <0f> ff 50 9d 4c 89 f7 e8 55 22 00 00 84 c0 74 09 e8 06 f1 ff ff
> [59697.280120] ---[ end trace cf42df41100f38cf ]---
> [59697.280251] BUG: Bad page state in process ksoftirqd/49 pfn:85537d
> [59697.280253] page:ffffea002154df40 count:0 mapcount:-1 mapping:
> (null) index:0xffff88085537db00
> [59697.280393] flags: 0x600000000000000()
> [59697.280510] raw: 0600000000000000 0000000000000000 ffff88085537db00
> 00000000fffffffe
> [59697.280511] raw: 0000000000000000 0000000100000001 0000000000000000
> 0000000000000000
> [59697.280511] page dumped because: nonzero mapcount
> [59697.280512] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
> [59697.280515] CPU: 49 PID: 257 Comm: ksoftirqd/49 Tainted: G W
> 4.13.0-rc4-next-20170808 #1
> [59697.280516] Call Trace:
> [59697.280521] dump_stack+0x4d/0x63
> [59697.280526] bad_page+0xf3/0x10f
> [59697.280528] check_new_page_bad+0x73/0x75
> [59697.280529] get_page_from_freelist+0x419/0x63f
> [59697.280532] ? ip_finish_output+0x11f/0x12b
> [59697.280533] __alloc_pages_nodemask+0xf2/0x187
> [59697.280536] ? ip_route_input_rcu+0x489/0x7d3
> [59697.280540] alloc_pages_current+0x85/0x8c
> [59697.280542] new_slab+0xc2/0x2f7
> [59697.280544] ___slab_alloc+0x350/0x3cd
> [59697.280547] ? __build_skb+0x28/0xa4
> [59697.280550] ? __netif_receive_skb_core+0x325/0x4c0
> [59697.280551] __slab_alloc+0x12/0x17
> [59697.280552] ? __slab_alloc+0x12/0x17
> [59697.280554] kmem_cache_alloc+0x50/0x112
> [59697.280555] __build_skb+0x28/0xa4
> [59697.280556] build_skb+0x12/0x41
> [59697.280560] ixgbe_poll+0x6e4/0xeef
> [59697.280562] net_rx_action+0xd3/0x22d
> [59697.280563] __do_softirq+0xe4/0x23a
> [59697.280565] ? sort_range+0x1d/0x1d
> [59697.280566] run_ksoftirqd+0x15/0x2a
> [59697.280567] smpboot_thread_fn+0x128/0x13f
> [59697.280568] kthread+0xf7/0xfc
> [59697.280569] ? init_completion+0x24/0x24
> [59697.280572] ret_from_fork+0x22/0x30
> [59697.280573] Disabling lock debugging due to kernel taint
> [60087.124142] BUG: Bad page state in process ksoftirqd/50 pfn:84ed9f
> [60087.124145] page:ffffea00213b67c0 count:0 mapcount:-127 mapping:
> (null) index:0x0
> [60087.124279] flags: 0x600000000000000()
> [60087.124396] raw: 0600000000000000 0000000000000000 0000000000000000
> 00000000ffffff80
> [60087.124397] raw: ffffea0021a029a0 ffffea00215302a0 0000000000000000
> 0000000000000000
> [60087.124397] page dumped because: nonzero mapcount
> [60087.124398] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
> [60087.124403] CPU: 50 PID: 262 Comm: ksoftirqd/50 Tainted: G B W
> 4.13.0-rc4-next-20170808 #1
> [60087.124404] Call Trace:
> [60087.124411] dump_stack+0x4d/0x63
> [60087.124415] bad_page+0xf3/0x10f
> [60087.124417] free_pages_check+0x75/0x7f
> [60087.124419] __free_pages_ok+0xaf/0x158
> [60087.124420] page_frag_free+0x47/0x49
> [60087.124424] skb_free_head+0x19/0x22
> [60087.124425] skb_release_data+0x89/0x90
> [60087.124427] skb_release_all+0x1f/0x22
> [60087.124428] _kfree_skb_defer+0x1e/0x5b
> [60087.124430] napi_consume_skb+0x3e/0x41
> [60087.124434] ixgbe_poll+0xe7/0xeef
> [60087.124437] net_rx_action+0xd3/0x22d
> [60087.124439] __do_softirq+0xe4/0x23a
> [60087.124443] ? sort_range+0x1d/0x1d
> [60087.124443] run_ksoftirqd+0x15/0x2a
> [60087.124444] smpboot_thread_fn+0x128/0x13f
> [60087.124447] kthread+0xf7/0xfc
> [60087.124448] ? init_completion+0x24/0x24
> [60087.124452] ret_from_fork+0x22/0x30
> [60175.047713] BUG: Bad page state in process perf pfn:84ed9f
> [60175.047715] page:ffffea00213b67c0 count:44363 mapcount:0 mapping:
> (null) index:0x0
> [60175.047849] flags: 0x600000000000000()
> [60175.047964] raw: 0600000000000000 0000000000000000 0000000000000000
> 0000ad4bffffffff
> [60175.047965] raw: dead000000000100 dead000000000200 0000000000000000
> 0000000000000000
> [60175.047965] page dumped because: nonzero _count
> [60175.047966] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
> [60175.047970] CPU: 28 PID: 8325 Comm: perf Tainted: G B W
> 4.13.0-rc4-next-20170808 #1
> [60175.047971] Call Trace:
> [60175.047980] dump_stack+0x4d/0x63
> [60175.047986] bad_page+0xf3/0x10f
> [60175.047988] check_new_page_bad+0x73/0x75
> [60175.047989] get_page_from_freelist+0x2a9/0x63f
> [60175.047990] __alloc_pages_nodemask+0xf2/0x187
> [60175.047994] new_slab+0xd6/0x2f7
> [60175.047996] ___slab_alloc+0x350/0x3cd
> [60175.048000] ? kzalloc_node+0xf/0x11
> [60175.048001] ? __alloc_pages_nodemask+0xf2/0x187
> [60175.048002] __slab_alloc+0x12/0x17
> [60175.048004] ? __slab_alloc+0x12/0x17
> [60175.048005] __kmalloc_node+0x92/0x10c
> [60175.048007] kzalloc_node+0xf/0x11
> [60175.048008] reserve_ds_buffers+0x90/0x30d
> [60175.048010] x86_reserve_hardware+0xbd/0xcd
> [60175.048011] x86_pmu_event_init+0x50/0x1c9
> [60175.048013] perf_try_init_event+0x41/0x72
> [60175.048014] perf_event_alloc+0x36f/0x61a
> [60175.048016] SYSC_perf_event_open+0x3fa/0xb22
> [60175.048018] SyS_perf_event_open+0x9/0xb
> [60175.048022] entry_SYSCALL_64_fastpath+0x13/0x94
> [60175.048023] RIP: 0033:0x7f4b74add5c9
> [60175.048024] RSP: 002b:00007ffe273ff6f8 EFLAGS: 00000202 ORIG_RAX:
> 000000000000012a
> [60175.048025] RAX: ffffffffffffffda RBX: 00007ffe273ff830 RCX:
> 00007f4b74add5c9
> [60175.048026] RDX: 00000000ffffffff RSI: 0000000000000000 RDI:
> 00007ffe273ff740
> [60175.048027] RBP: 00007ffe273ff800 R08: 0000000000000000 R09:
> 00007ffe273ffa40
> [60175.048027] R10: 00000000ffffffff R11: 0000000000000202 R12:
> 0000000000000000
> [60175.048028] R13: 00007ffe273ffaf0 R14: 0000000000000001 R15:
> 00007ffe274050b0
> [60205.531673] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
> [60205.775698] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps, Flow
> Control: None
> [60226.155671] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
> [60226.399691] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps, Flow
> Control: None
> [60401.551685] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
> [60401.795723] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps, Flow
> Control: None
> [60580.967690] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
> [60581.315732] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps, Flow
> Control: None
>
> [60961.112120] BUG: Bad page state in process ksoftirqd/44 pfn:855f2f
> [60961.112123] page:ffffea002157cbc0 count:51910 mapcount:0 mapping:
> (null) index:0x0
> [60961.112259] flags: 0x600000000000000()
> [60961.112375] raw: 0600000000000000 0000000000000000 0000000000000000
> 0000cac6ffffffff
> [60961.112376] raw: dead000000000100 dead000000000200 0000000000000000
> 0000000000000000
> [60961.112377] page dumped because: nonzero _count
> [60961.112377] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
> [60961.112381] CPU: 44 PID: 232 Comm: ksoftirqd/44 Tainted: G B W
> 4.13.0-rc4-next-20170808 #1
> [60961.112382] Call Trace:
> [60961.112390] dump_stack+0x4d/0x63
> [60961.112394] bad_page+0xf3/0x10f
> [60961.112396] check_new_page_bad+0x73/0x75
> [60961.112397] get_page_from_freelist+0x2a9/0x63f
> [60961.112398] __alloc_pages_nodemask+0xf2/0x187
> [60961.112403] alloc_pages_current+0x85/0x8c
> [60961.112405] new_slab+0xc2/0x2f7
> [60961.112407] ___slab_alloc+0x350/0x3cd
> [60961.112409] ? fq_enqueue+0x24e/0x3e3 [sch_fq]
> [60961.112411] __slab_alloc+0x12/0x17
> [60961.112412] ? __slab_alloc+0x12/0x17
> [60961.112413] kmem_cache_alloc+0x50/0x112
> [60961.112414] fq_enqueue+0x24e/0x3e3 [sch_fq]
> [60961.112419] ? ixgbe_select_queue+0x15/0x17
> [60961.112422] __dev_queue_xmit+0x2a5/0x4b9
> [60961.112423] dev_queue_xmit+0xb/0xd
> [60961.112423] ? dev_queue_xmit+0xb/0xd
> [60961.112425] vlan_dev_hard_start_xmit+0x81/0xaa
> [60961.112426] dev_hard_start_xmit+0xc3/0x197
> [60961.112427] __dev_queue_xmit+0x38d/0x4b9
> [60961.112429] ? eth_header+0x27/0xab
> [60961.112429] dev_queue_xmit+0xb/0xd
> [60961.112430] ? dev_queue_xmit+0xb/0xd
> [60961.112432] neigh_connected_output+0x9b/0xb2
> [60961.112436] ip_finish_output2+0x24e/0x292
> [60961.112437] ip_finish_output+0x11f/0x12b
> [60961.112438] ip_output+0x56/0xa7
> [60961.112441] ? ip_route_input_rcu+0x489/0x7d3
> [60961.112442] ip_forward_finish+0x53/0x58
> [60961.112443] ip_forward+0x2ff/0x350
> [60961.112443] ? ip_frag_mem+0x1e/0x1e
> [60961.112444] ip_rcv_finish+0x27f/0x28a
> [60961.112445] ip_rcv+0x2c0/0x30d
> [60961.112448] __netif_receive_skb_core+0x325/0x4c0
> [60961.112449] __netif_receive_skb+0x18/0x5a
> [60961.112450] ? dev_gro_receive+0x2a9/0x3b4
> [60961.112451] ? __netif_receive_skb+0x18/0x5a
> [60961.112452] netif_receive_skb_internal+0x4b/0x96
> [60961.112453] napi_gro_receive+0x75/0xcc
> [60961.112455] ixgbe_poll+0xed8/0xeef
> [60961.112459] ? __printk_ratelimit+0x8/0x15
> [60961.112460] net_rx_action+0xd3/0x22d
> [60961.112462] __do_softirq+0xe4/0x23a
> [60961.112465] ? sort_range+0x1d/0x1d
> [60961.112466] run_ksoftirqd+0x15/0x2a
> [60961.112467] smpboot_thread_fn+0x128/0x13f
> [60961.112470] kthread+0xf7/0xfc
> [60961.112471] ? init_completion+0x24/0x24
> [60961.112475] ret_from_fork+0x22/0x30
> [60983.541418] capability: warning: `turbostat' uses 32-bit capabilities
> (legacy support in use)
> [61179.159683] ixgbe 0000:d8:00.1 enp216s0f1: detected SFP+: 4
> [61179.503705] ixgbe 0000:d8:00.1 enp216s0f1: NIC Link is Up 10 Gbps, Flow
> Control: None
> [61183.212237] BUG: Bad page state in process ksoftirqd/52 pfn:855f2f
> [61183.212240] page:ffffea002157cbc0 count:-1 mapcount:0 mapping:
> (null) index:0x0
> [61183.212375] flags: 0x600000000000000()
> [61183.212492] raw: 0600000000000000 0000000000000000 0000000000000000
> ffffffffffffffff
> [61183.212493] raw: dead000000000100 dead000000000200 0000000000000000
> 0000000000000000
> [61183.212493] page dumped because: nonzero _count
> [61183.212494] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
> [61183.212498] CPU: 52 PID: 272 Comm: ksoftirqd/52 Tainted: G B W
> 4.13.0-rc4-next-20170808 #1
> [61183.212500] Call Trace:
> [61183.212507] dump_stack+0x4d/0x63
> [61183.212512] bad_page+0xf3/0x10f
> [61183.212514] check_new_page_bad+0x73/0x75
> [61183.212515] get_page_from_freelist+0x2a9/0x63f
> [61183.212517] __alloc_pages_nodemask+0xf2/0x187
> [61183.212523] ixgbe_alloc_rx_buffers+0x77/0x1bb
> [61183.212524] ixgbe_poll+0x421/0xeef
> [61183.212529] ? cfs_rq_util_change+0x1e/0x20
> [61183.212532] net_rx_action+0xd3/0x22d
> [61183.212534] __do_softirq+0xe4/0x23a
> [61183.212536] ? sort_range+0x1d/0x1d
> [61183.212537] run_ksoftirqd+0x15/0x2a
> [61183.212538] smpboot_thread_fn+0x128/0x13f
> [61183.212540] kthread+0xf7/0xfc
> [61183.212541] ? init_completion+0x24/0x24
> [61183.212546] ret_from_fork+0x22/0x30
> [61183.283732] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
> [61183.527747] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps, Flow
> Control: None
> [61223.651684] ixgbe 0000:d8:00.1 enp216s0f1: detected SFP+: 4
> [61223.891712] ixgbe 0000:d8:00.1 enp216s0f1: NIC Link is Up 10 Gbps, Flow
> Control: None
> [61228.651748] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
> [61228.891759] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps, Flow
> Control: None
> [61408.583698] ixgbe 0000:d8:00.1 enp216s0f1: detected SFP+: 4
> [61408.831720] ixgbe 0000:d8:00.1 enp216s0f1: NIC Link is Up 10 Gbps, Flow
> Control: None
> [61414.003718] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
> [61414.247764] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps, Flow
> Control: None
> [63318.496105] igb 0000:18:00.3 enp24s0f3: Reset adapter
> [63321.828156] igb 0000:18:00.3 enp24s0f3: igb: enp24s0f3 NIC Link is Up
> 1000 Mbps Full Duplex, Flow Control: RX
>
>
>
> W dniu 2017-08-10 o 01:27, Cong Wang pisze:
>
>> On Wed, Aug 9, 2017 at 8:50 AM, Paweł Staszewski <pstaszewski@itcare.pl>
>> wrote:
>>>
>>>
>>>
>>> [60961.112120] BUG: Bad page state in process ksoftirqd/44 pfn:855f2f
>>> [60961.112123] page:ffffea002157cbc0 count:51910 mapcount:0 mapping:
>>> (null) index:0x0
>>> [60961.112259] flags: 0x600000000000000()
>>> [60961.112375] raw: 0600000000000000 0000000000000000 0000000000000000
>>> 0000cac6ffffffff
>>> [60961.112376] raw: dead000000000100 dead000000000200 0000000000000000
>>> 0000000000000000
>>> [60961.112377] page dumped because: nonzero _count
>>> [60961.112377] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
>>> [60961.112381] CPU: 44 PID: 232 Comm: ksoftirqd/44 Tainted: G B W
>>> 4.13.0-rc4-next-20170808 #1
>>> [60961.112382] Call Trace:
>>> [60961.112390] dump_stack+0x4d/0x63
>>> [60961.112394] bad_page+0xf3/0x10f
>>> [60961.112396] check_new_page_bad+0x73/0x75
>>> [60961.112397] get_page_from_freelist+0x2a9/0x63f
>>> [60961.112398] __alloc_pages_nodemask+0xf2/0x187
>>> [60961.112403] alloc_pages_current+0x85/0x8c
>>> [60961.112405] new_slab+0xc2/0x2f7
>>> [60961.112407] ___slab_alloc+0x350/0x3cd
>>> [60961.112409] ? fq_enqueue+0x24e/0x3e3 [sch_fq]
>>> [60961.112411] __slab_alloc+0x12/0x17
>>> [60961.112412] ? __slab_alloc+0x12/0x17
>>> [60961.112413] kmem_cache_alloc+0x50/0x112
>>> [60961.112414] fq_enqueue+0x24e/0x3e3 [sch_fq]
>>> [60961.112419] ? ixgbe_select_queue+0x15/0x17
>>> [60961.112422] __dev_queue_xmit+0x2a5/0x4b9
>>> [60961.112423] dev_queue_xmit+0xb/0xd
>>
>>
>> Is this the first stack trace in your dmesg?
>>
>> It doesn't look like a bug in sch_fq, but like we have
>> a bad mm page somewhere else, perhaps ixgbe driver.
>>
>>
>>
>>> [60961.112423] ? dev_queue_xmit+0xb/0xd
>>> [60961.112425] vlan_dev_hard_start_xmit+0x81/0xaa
>>> [60961.112426] dev_hard_start_xmit+0xc3/0x197
>>> [60961.112427] __dev_queue_xmit+0x38d/0x4b9
>>> [60961.112429] ? eth_header+0x27/0xab
>>> [60961.112429] dev_queue_xmit+0xb/0xd
>>> [60961.112430] ? dev_queue_xmit+0xb/0xd
>>> [60961.112432] neigh_connected_output+0x9b/0xb2
>>> [60961.112436] ip_finish_output2+0x24e/0x292
>>> [60961.112437] ip_finish_output+0x11f/0x12b
>>> [60961.112438] ip_output+0x56/0xa7
>>> [60961.112441] ? ip_route_input_rcu+0x489/0x7d3
>>> [60961.112442] ip_forward_finish+0x53/0x58
>>> [60961.112443] ip_forward+0x2ff/0x350
>>> [60961.112443] ? ip_frag_mem+0x1e/0x1e
>>> [60961.112444] ip_rcv_finish+0x27f/0x28a
>>> [60961.112445] ip_rcv+0x2c0/0x30d
>>> [60961.112448] __netif_receive_skb_core+0x325/0x4c0
>>> [60961.112449] __netif_receive_skb+0x18/0x5a
>>> [60961.112450] ? dev_gro_receive+0x2a9/0x3b4
>>> [60961.112451] ? __netif_receive_skb+0x18/0x5a
>>> [60961.112452] netif_receive_skb_internal+0x4b/0x96
>>> [60961.112453] napi_gro_receive+0x75/0xcc
>>> [60961.112455] ixgbe_poll+0xed8/0xeef
>>> [60961.112459] ? __printk_ratelimit+0x8/0x15
>>> [60961.112460] net_rx_action+0xd3/0x22d
>>> [60961.112462] __do_softirq+0xe4/0x23a
>>> [60961.112465] ? sort_range+0x1d/0x1d
>>> [60961.112466] run_ksoftirqd+0x15/0x2a
>>> [60961.112467] smpboot_thread_fn+0x128/0x13f
>>> [60961.112470] kthread+0xf7/0xfc
>>> [60961.112471] ? init_completion+0x24/0x24
>>> [60961.112475] ret_from_fork+0x22/0x30
>>> [60983.541418] capability: warning: `turbostat' uses 32-bit capabilities
>>> (legacy support in use)
>>> [61179.159683] ixgbe 0000:d8:00.1 enp216s0f1: detected SFP+: 4
>>> [61179.503705] ixgbe 0000:d8:00.1 enp216s0f1: NIC Link is Up 10 Gbps,
>>> Flow
>>> Control: None
>>> [61183.212237] BUG: Bad page state in process ksoftirqd/52 pfn:855f2f
>>> [61183.212240] page:ffffea002157cbc0 count:-1 mapcount:0 mapping:
>>> (null) index:0x0
>>> [61183.212375] flags: 0x600000000000000()
>>> [61183.212492] raw: 0600000000000000 0000000000000000 0000000000000000
>>> ffffffffffffffff
>>> [61183.212493] raw: dead000000000100 dead000000000200 0000000000000000
>>> 0000000000000000
>>> [61183.212493] page dumped because: nonzero _count
>>> [61183.212494] Modules linked in: sch_fq x86_pkg_temp_thermal ipmi_si
>>> [61183.212498] CPU: 52 PID: 272 Comm: ksoftirqd/52 Tainted: G B W
>>> 4.13.0-rc4-next-20170808 #1
>>> [61183.212500] Call Trace:
>>> [61183.212507] dump_stack+0x4d/0x63
>>> [61183.212512] bad_page+0xf3/0x10f
>>> [61183.212514] check_new_page_bad+0x73/0x75
>>> [61183.212515] get_page_from_freelist+0x2a9/0x63f
>>> [61183.212517] __alloc_pages_nodemask+0xf2/0x187
>>> [61183.212523] ixgbe_alloc_rx_buffers+0x77/0x1bb
>>> [61183.212524] ixgbe_poll+0x421/0xeef
>>> [61183.212529] ? cfs_rq_util_change+0x1e/0x20
>>> [61183.212532] net_rx_action+0xd3/0x22d
>>> [61183.212534] __do_softirq+0xe4/0x23a
>>> [61183.212536] ? sort_range+0x1d/0x1d
>>> [61183.212537] run_ksoftirqd+0x15/0x2a
>>> [61183.212538] smpboot_thread_fn+0x128/0x13f
>>> [61183.212540] kthread+0xf7/0xfc
>>> [61183.212541] ? init_completion+0x24/0x24
>>> [61183.212546] ret_from_fork+0x22/0x30
>>> [61183.283732] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
>>> [61183.527747] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps,
>>> Flow
>>> Control: None
>>> [61223.651684] ixgbe 0000:d8:00.1 enp216s0f1: detected SFP+: 4
>>> [61223.891712] ixgbe 0000:d8:00.1 enp216s0f1: NIC Link is Up 10 Gbps,
>>> Flow
>>> Control: None
>>> [61228.651748] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
>>> [61228.891759] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps,
>>> Flow
>>> Control: None
>>> [61408.583698] ixgbe 0000:d8:00.1 enp216s0f1: detected SFP+: 4
>>> [61408.831720] ixgbe 0000:d8:00.1 enp216s0f1: NIC Link is Up 10 Gbps,
>>> Flow
>>> Control: None
>>> [61414.003718] ixgbe 0000:d8:00.0 enp216s0f0: detected SFP+: 3
>>> [61414.247764] ixgbe 0000:d8:00.0 enp216s0f0: NIC Link is Up 10 Gbps,
>>> Flow
>>> Control: None
>>> [63318.496105] igb 0000:18:00.3 enp24s0f3: Reset adapter
>>> [63321.828156] igb 0000:18:00.3 enp24s0f3: igb: enp24s0f3 NIC Link is Up
>>> 1000 Mbps Full Duplex, Flow Control: RX
>>>
>>>
>>>
>>>
>>>
>>> If matters configuration below:
>>>
>>> tc -s -d qdisc show
>>> qdisc noqueue 0: dev lo root refcnt 2
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> qdisc mq 0: dev enp24s0f3 root
>>> Sent 10595979 bytes 44275 pkt (dropped 0, overlimits 0 requeues 7)
>>> backlog 0b 0p requeues 7
>>> qdisc pfifo_fast 0: dev enp24s0f3 parent :8 bands 3 priomap 1 2 2 2 1 2
>>> 0 0
>>> 1 1 1 1 1 1 1 1
>>> Sent 2562064 bytes 7304 pkt (dropped 0, overlimits 0 requeues 1)
>>> backlog 0b 0p requeues 1
>>> qdisc pfifo_fast 0: dev enp24s0f3 parent :7 bands 3 priomap 1 2 2 2 1 2
>>> 0 0
>>> 1 1 1 1 1 1 1 1
>>> Sent 152292 bytes 3589 pkt (dropped 0, overlimits 0 requeues 2)
>>> backlog 0b 0p requeues 2
>>> qdisc pfifo_fast 0: dev enp24s0f3 parent :6 bands 3 priomap 1 2 2 2 1 2
>>> 0 0
>>> 1 1 1 1 1 1 1 1
>>> Sent 7298 bytes 15 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> qdisc pfifo_fast 0: dev enp24s0f3 parent :5 bands 3 priomap 1 2 2 2 1 2
>>> 0 0
>>> 1 1 1 1 1 1 1 1
>>> Sent 5042 bytes 5 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> qdisc pfifo_fast 0: dev enp24s0f3 parent :4 bands 3 priomap 1 2 2 2 1 2
>>> 0 0
>>> 1 1 1 1 1 1 1 1
>>> Sent 3194 bytes 4 pkt (dropped 0, overlimits 0 requeues 1)
>>> backlog 0b 0p requeues 1
>>> qdisc pfifo_fast 0: dev enp24s0f3 parent :3 bands 3 priomap 1 2 2 2 1 2
>>> 0 0
>>> 1 1 1 1 1 1 1 1
>>> Sent 5386576 bytes 13206 pkt (dropped 0, overlimits 0 requeues 1)
>>> backlog 0b 0p requeues 1
>>> qdisc pfifo_fast 0: dev enp24s0f3 parent :2 bands 3 priomap 1 2 2 2 1 2
>>> 0 0
>>> 1 1 1 1 1 1 1 1
>>> Sent 6286 bytes 24 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> qdisc pfifo_fast 0: dev enp24s0f3 parent :1 bands 3 priomap 1 2 2 2 1 2
>>> 0 0
>>> 1 1 1 1 1 1 1 1
>>> Sent 2473227 bytes 20128 pkt (dropped 0, overlimits 0 requeues 2)
>>> backlog 0b 0p requeues 2
>>> qdisc mq 1: dev enp216s0f0 root
>>> Sent 140 bytes 2 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> qdisc fq 831c: dev enp216s0f0 parent 1:a limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8320: dev enp216s0f0 parent 1:e limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 831e: dev enp216s0f0 parent 1:c limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8322: dev enp216s0f0 parent 1:10 limit 8192p flow_limit 100p
>>> buckets 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate
>>> 10Gbit refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8313: dev enp216s0f0 parent 1:1 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8315: dev enp216s0f0 parent 1:3 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8317: dev enp216s0f0 parent 1:5 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 831b: dev enp216s0f0 parent 1:9 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8319: dev enp216s0f0 parent 1:7 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 140 bytes 2 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 1 flows (1 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 831d: dev enp216s0f0 parent 1:b limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 831f: dev enp216s0f0 parent 1:d limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8321: dev enp216s0f0 parent 1:f limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8316: dev enp216s0f0 parent 1:4 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8314: dev enp216s0f0 parent 1:2 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 8318: dev enp216s0f0 parent 1:6 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc fq 831a: dev enp216s0f0 parent 1:8 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>> 0 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 0 throttled
>>> qdisc mq 1: dev enp216s0f1 root
>>> Sent 5724464060294 bytes 3017574303 pkt (dropped 261703917, overlimits
>>> 0
>>> requeues 1588)
>>> backlog 19340684b 68101p requeues 1588
>>> qdisc fq 8331: dev enp216s0f1 parent 1:f limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357754034478 bytes 1261904590 pkt (dropped 16345926, overlimits 0
>>> requeues 99)
>>> backlog 1190528b 4198p requeues 99
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 15 throttled, 2238 ns latency, 16345926 flows_plimit
>>> qdisc fq 8324: dev enp216s0f1 parent 1:2 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357941986556 bytes 1265190082 pkt (dropped 16334441, overlimits 0
>>> requeues 114)
>>> backlog 1203308b 4237p requeues 114
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 56 throttled, 1988 ns latency, 16334441 flows_plimit
>>> qdisc fq 8326: dev enp216s0f1 parent 1:4 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357756741808 bytes 1261951272 pkt (dropped 16352852, overlimits 0
>>> requeues 108)
>>> backlog 1195356b 4210p requeues 108
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 10 throttled, 1652 ns latency, 16352852 flows_plimit
>>> qdisc fq 832a: dev enp216s0f1 parent 1:8 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357754168172 bytes 1261906634 pkt (dropped 16375523, overlimits 0
>>> requeues 93)
>>> backlog 1191664b 4196p requeues 93
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 4 throttled, 1722 ns latency, 16375523 flows_plimit
>>> qdisc fq 8328: dev enp216s0f1 parent 1:6 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357755800928 bytes 1261934832 pkt (dropped 16297692, overlimits 0
>>> requeues 89)
>>> backlog 1206432b 4248p requeues 89
>>> 65 flows (1 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 4 throttled, 1520 ns latency, 16297692 flows_plimit
>>> qdisc fq 832c: dev enp216s0f1 parent 1:a limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357757943172 bytes 1261969807 pkt (dropped 16393936, overlimits 0
>>> requeues 97)
>>> backlog 1185984b 4176p requeues 97
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 4 throttled, 1257 ns latency, 16393936 flows_plimit
>>> qdisc fq 832e: dev enp216s0f1 parent 1:c limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357754956814 bytes 1261920403 pkt (dropped 16373257, overlimits 0
>>> requeues 111)
>>> backlog 1184848b 4172p requeues 111
>>> 65 flows (1 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 11 throttled, 2070 ns latency, 16373257 flows_plimit
>>> qdisc fq 8332: dev enp216s0f1 parent 1:10 limit 8192p flow_limit 100p
>>> buckets 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate
>>> 10Gbit refill_delay 40.0ms
>>> Sent 357754779582 bytes 1261916755 pkt (dropped 16306559, overlimits 0
>>> requeues 80)
>>> backlog 1151336b 4054p requeues 80
>>> 65 flows (1 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 3 throttled, 1530 ns latency, 16306559 flows_plimit
>>> qdisc fq 8330: dev enp216s0f1 parent 1:e limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357754801422 bytes 1261919138 pkt (dropped 16360298, overlimits 0
>>> requeues 68)
>>> backlog 1266072b 4457p requeues 68
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 7 throttled, 1114 ns latency, 16360298 flows_plimit
>>> qdisc fq 8325: dev enp216s0f1 parent 1:3 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357756968400 bytes 1261953663 pkt (dropped 16377069, overlimits 0
>>> requeues 84)
>>> backlog 1267492b 4463p requeues 84
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 6 throttled, 2470 ns latency, 16377069 flows_plimit
>>> qdisc fq 8323: dev enp216s0f1 parent 1:1 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357944308424 bytes 1265224502 pkt (dropped 16351766, overlimits 0
>>> requeues 125)
>>> backlog 1227164b 4321p requeues 125
>>> 65 flows (1 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 58 throttled, 2143 ns latency, 16351766 flows_plimit
>>> qdisc fq 8327: dev enp216s0f1 parent 1:5 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357756634544 bytes 1261949446 pkt (dropped 16354220, overlimits 0
>>> requeues 114)
>>> backlog 1176896b 4143p requeues 114
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 5 throttled, 2274 ns latency, 16354220 flows_plimit
>>> qdisc fq 8329: dev enp216s0f1 parent 1:7 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357755020876 bytes 1261921756 pkt (dropped 16366535, overlimits 0
>>> requeues 108)
>>> backlog 1171216b 4124p requeues 108
>>> 65 flows (1 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 3 throttled, 932 ns latency, 16366535 flows_plimit
>>> qdisc fq 832d: dev enp216s0f1 parent 1:b limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357755470474 bytes 1261930198 pkt (dropped 16347462, overlimits 0
>>> requeues 99)
>>> backlog 1255848b 4422p requeues 99
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 5 throttled, 1699 ns latency, 16347462 flows_plimit
>>> qdisc fq 832b: dev enp216s0f1 parent 1:9 limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357754977102 bytes 1261920885 pkt (dropped 16407954, overlimits 0
>>> requeues 92)
>>> backlog 1260108b 4437p requeues 92
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 5 throttled, 1638 ns latency, 16407954 flows_plimit
>>> qdisc fq 832f: dev enp216s0f1 parent 1:d limit 8192p flow_limit 100p
>>> buckets
>>> 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 maxrate 10Gbit
>>> refill_delay 40.0ms
>>> Sent 357755499918 bytes 1261929638 pkt (dropped 16358427, overlimits 0
>>> requeues 107)
>>> backlog 1194220b 4205p requeues 107
>>> 64 flows (0 inactive, 0 throttled)
>>> 0 gc, 0 highprio, 8 throttled, 2257 ns latency, 16358427 flows_plimit
>>> qdisc noqueue 0: dev vlan1000 root refcnt 2
>>> Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
>>> backlog 0b 0p requeues 0
>>>
>>> ethtool -k enp216s0f1
>>> Features for enp216s0f1:
>>> Cannot get device udp-fragmentation-offload settings: Operation not
>>> supported
>>> rx-checksumming: on
>>> tx-checksumming: on
>>> tx-checksum-ipv4: off [fixed]
>>> tx-checksum-ip-generic: on
>>> tx-checksum-ipv6: off [fixed]
>>> tx-checksum-fcoe-crc: off [fixed]
>>> tx-checksum-sctp: on
>>> scatter-gather: on
>>> tx-scatter-gather: on
>>> tx-scatter-gather-fraglist: off [fixed]
>>> tcp-segmentation-offload: on
>>> tx-tcp-segmentation: on
>>> tx-tcp-ecn-segmentation: off [fixed]
>>> tx-tcp-mangleid-segmentation: on
>>> tx-tcp6-segmentation: on
>>> udp-fragmentation-offload: off
>>> generic-segmentation-offload: off
>>> generic-receive-offload: on
>>> large-receive-offload: off
>>> rx-vlan-offload: on
>>> tx-vlan-offload: on
>>> ntuple-filters: on
>>> receive-hashing: on
>>> highdma: on [fixed]
>>> rx-vlan-filter: on
>>> vlan-challenged: off [fixed]
>>> tx-lockless: off [fixed]
>>> netns-local: off [fixed]
>>> tx-gso-robust: off [fixed]
>>> tx-fcoe-segmentation: off [fixed]
>>> tx-gre-segmentation: on
>>> tx-gre-csum-segmentation: on
>>> tx-ipxip4-segmentation: on
>>> tx-ipxip6-segmentation: on
>>> tx-udp_tnl-segmentation: on
>>> tx-udp_tnl-csum-segmentation: on
>>> tx-gso-partial: on
>>> tx-sctp-segmentation: off [fixed]
>>> tx-esp-segmentation: off [fixed]
>>> fcoe-mtu: off [fixed]
>>> tx-nocache-copy: on
>>> loopback: off [fixed]
>>> rx-fcs: off [fixed]
>>> rx-all: off
>>> tx-vlan-stag-hw-insert: off [fixed]
>>> rx-vlan-stag-hw-parse: off [fixed]
>>> rx-vlan-stag-filter: off [fixed]
>>> l2-fwd-offload: off
>>> hw-tc-offload: on
>>> esp-hw-offload: off [fixed]
>>> esp-tx-csum-hw-offload: off [fixed]
>>> rx-udp_tunnel-port-offload: on
>>>
>>> ethtool -k enp216s0f0
>>> Features for enp216s0f0:
>>> Cannot get device udp-fragmentation-offload settings: Operation not
>>> supported
>>> rx-checksumming: on
>>> tx-checksumming: on
>>> tx-checksum-ipv4: off [fixed]
>>> tx-checksum-ip-generic: on
>>> tx-checksum-ipv6: off [fixed]
>>> tx-checksum-fcoe-crc: off [fixed]
>>> tx-checksum-sctp: on
>>> scatter-gather: on
>>> tx-scatter-gather: on
>>> tx-scatter-gather-fraglist: off [fixed]
>>> tcp-segmentation-offload: on
>>> tx-tcp-segmentation: on
>>> tx-tcp-ecn-segmentation: off [fixed]
>>> tx-tcp-mangleid-segmentation: on
>>> tx-tcp6-segmentation: on
>>> udp-fragmentation-offload: off
>>> generic-segmentation-offload: off
>>> generic-receive-offload: on
>>> large-receive-offload: off
>>> rx-vlan-offload: on
>>> tx-vlan-offload: on
>>> ntuple-filters: on
>>> receive-hashing: on
>>> highdma: on [fixed]
>>> rx-vlan-filter: on
>>> vlan-challenged: off [fixed]
>>> tx-lockless: off [fixed]
>>> netns-local: off [fixed]
>>> tx-gso-robust: off [fixed]
>>> tx-fcoe-segmentation: off [fixed]
>>> tx-gre-segmentation: on
>>> tx-gre-csum-segmentation: on
>>> tx-ipxip4-segmentation: on
>>> tx-ipxip6-segmentation: on
>>> tx-udp_tnl-segmentation: on
>>> tx-udp_tnl-csum-segmentation: on
>>> tx-gso-partial: on
>>> tx-sctp-segmentation: off [fixed]
>>> tx-esp-segmentation: off [fixed]
>>> fcoe-mtu: off [fixed]
>>> tx-nocache-copy: on
>>> loopback: off [fixed]
>>> rx-fcs: off [fixed]
>>> rx-all: off
>>> tx-vlan-stag-hw-insert: off [fixed]
>>> rx-vlan-stag-hw-parse: off [fixed]
>>> rx-vlan-stag-filter: off [fixed]
>>> l2-fwd-offload: off
>>> hw-tc-offload: off
>>> esp-hw-offload: off [fixed]
>>> esp-tx-csum-hw-offload: off [fixed]
>>> rx-udp_tunnel-port-offload: on
>>>
>>>
>
^ permalink raw reply
* Kernel 4.13.0-rc4-next-20170811 - IP Routing / Forwarding performance vs Core/RSS number / HT on
From: Paweł Staszewski @ 2017-08-11 17:51 UTC (permalink / raw)
To: Linux Kernel Network Developers
Hi
I made some tests for performance comparison.
Tested HW (FORWARDING HOST):
Intel(R) Xeon(R) Gold 6132 CPU @ 2.60GHz
Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
Test diagram:
TRAFFIC GENERATOR (ethX) -> (enp216s0f0 - RX Traffic) FORWARDING HOST
(enp216s0f1(vlan1000) - TX Traffic) -> (ethY) SINK
Forwarder traffic: UDP random ports from 9 to 19 with random hosts from
172.16.0.1 to 172.16.0.255
TRAFFIC GENERATOR TX is stable 9.9Mpps (in kernel pktgen)
Settings used for FORWARDING HOST (changed param. was only number of RSS
combined queues + set affinity assignment for them to fit with first
numa node where 2x10G port card is installed)
ixgbe driver used from kernel (in-kernel build - not a module)
#!/bin/sh
ifc='enp216s0f0 enp216s0f1'
for i in $ifc
do
ip link set up dev $i
ethtool -A $i autoneg off rx off tx off
ethtool -G $i rx 4096 tx 1024
ip link set $i txqueuelen 1000
ethtool -C $i rx-usecs 10
ethtool -L $i combined 16
ethtool -K $i gro on tso on gso off sg on l2-fwd-offload off
tx-nocache-copy on ntuple on
ethtool -N $i rx-flow-hash udp4 sdfn
done
ip link set up dev enp216s0f0
ip link set up dev enp216s0f1
ip a a 10.0.0.1/30 dev enp216s0f0
ip link add link enp216s0f1 name vlan1000 type vlan id 1000
ip link set up dev vlan1000
ip a a 10.0.0.5/30 dev vlan1000
ip route add 172.16.0.0/12 via 10.0.0.6
./set_irq_affinity.sh -x 14-27,42-43 enp216s0f0
./set_irq_affinity.sh -x 14-27,42-43 enp216s0f1
#cat /sys/devices/system/node/node1/cpulist
#14-27,42-55
#cat /sys/devices/system/node/node0/cpulist
#0-13,28-41
#################################################
Looks like forwarding performance when using vlans on ixgbe is less that
without vlans for about 30-40% (wondering if this is some vlan
offloading problem and ixgbe)
settings below:
ethtool -k enp216s0f0
Features for enp216s0f0:
Cannot get device udp-fragmentation-offload settings: Operation not
supported
rx-checksumming: on
tx-checksumming: on
tx-checksum-ipv4: off [fixed]
tx-checksum-ip-generic: on
tx-checksum-ipv6: off [fixed]
tx-checksum-fcoe-crc: off [fixed]
tx-checksum-sctp: on
scatter-gather: on
tx-scatter-gather: on
tx-scatter-gather-fraglist: off [fixed]
tcp-segmentation-offload: on
tx-tcp-segmentation: on
tx-tcp-ecn-segmentation: off [fixed]
tx-tcp-mangleid-segmentation: on
tx-tcp6-segmentation: on
udp-fragmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: on
receive-hashing: on
highdma: on [fixed]
rx-vlan-filter: on
vlan-challenged: off [fixed]
tx-lockless: off [fixed]
netns-local: off [fixed]
tx-gso-robust: off [fixed]
tx-fcoe-segmentation: off [fixed]
tx-gre-segmentation: on
tx-gre-csum-segmentation: on
tx-ipxip4-segmentation: on
tx-ipxip6-segmentation: on
tx-udp_tnl-segmentation: on
tx-udp_tnl-csum-segmentation: on
tx-gso-partial: on
tx-sctp-segmentation: off [fixed]
tx-esp-segmentation: off [fixed]
fcoe-mtu: off [fixed]
tx-nocache-copy: on
loopback: off [fixed]
rx-fcs: off [fixed]
rx-all: off
tx-vlan-stag-hw-insert: off [fixed]
rx-vlan-stag-hw-parse: off [fixed]
rx-vlan-stag-filter: off [fixed]
l2-fwd-offload: off
hw-tc-offload: off
esp-hw-offload: off [fixed]
esp-tx-csum-hw-offload: off [fixed]
rx-udp_tunnel-port-offload: on
Another thing is that forwarding performance does not scale with number
of cores when 7+ cores are reached
perf top:
PerfTop: 77835 irqs/sec kernel:99.7% exact: 0.0% [4000Hz
cycles], (all, 56 CPUs)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
16.32% [kernel] [k] skb_dst_force
16.30% [kernel] [k] dst_release
15.11% [kernel] [k] rt_cache_valid
12.62% [kernel] [k] ipv4_mtu
5.60% [kernel] [k] do_raw_spin_lock
3.03% [kernel] [k] fib_table_lookup
2.70% [kernel] [k] ip_finish_output2
2.10% [kernel] [k] dev_gro_receive
1.89% [kernel] [k] eth_type_trans
1.81% [kernel] [k] ixgbe_poll
1.15% [kernel] [k] ixgbe_xmit_frame_ring
1.06% [kernel] [k] __build_skb
1.04% [kernel] [k] __dev_queue_xmit
0.97% [kernel] [k] ip_rcv
0.78% [kernel] [k] netif_skb_features
0.74% [kernel] [k] ipt_do_table
0.70% [kernel] [k] acpi_processor_ffh_cstate_enter
0.64% [kernel] [k] ip_forward
0.59% [kernel] [k] __netif_receive_skb_core
0.55% [kernel] [k] dev_hard_start_xmit
0.53% [kernel] [k] ip_route_input_rcu
0.53% [kernel] [k] ip_rcv_finish
0.51% [kernel] [k] page_frag_free
0.50% [kernel] [k] kmem_cache_alloc
0.50% [kernel] [k] udp_v4_early_demux
0.44% [kernel] [k] skb_release_data
0.42% [kernel] [k] inet_gro_receive
0.40% [kernel] [k] sch_direct_xmit
0.39% [kernel] [k] __local_bh_enable_ip
0.33% [kernel] [k] netdev_pick_tx
0.33% [kernel] [k] validate_xmit_skb
0.28% [kernel] [k] fib_validate_source
0.27% [kernel] [k] deliver_ptype_list_skb
0.25% [kernel] [k] eth_header
0.23% [kernel] [k] get_dma_ops
0.22% [kernel] [k] skb_network_protocol
0.21% [kernel] [k] ip_output
0.21% [kernel] [k] vlan_dev_hard_start_xmit
0.20% [kernel] [k] ixgbe_alloc_rx_buffers
0.18% [kernel] [k] nf_hook_slow
0.18% [kernel] [k] apic_timer_interrupt
0.18% [kernel] [k] virt_to_head_page
0.18% [kernel] [k] build_skb
0.16% [kernel] [k] swiotlb_map_page
0.16% [kernel] [k] ip_finish_output
0.16% [kernel] [k] udp4_gro_receive
RESULTS:
CSV format - delimeter ";"
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;1;64;1470912;88247040;1470720;85305530
1;1;64;1470912;88285440;1470977;85335110
2;1;64;1470464;88247040;1470402;85290508
3;1;64;1471424;88262400;1471230;85353728
4;1;64;1468736;88166400;1468672;85201652
5;1;64;1470016;88181760;1469949;85234944
6;1;64;1470720;88247040;1470466;85290624
7;1;64;1471232;88277760;1471167;85346246
8;1;64;1469184;88170240;1469249;85216326
9;1;64;1470592;88227840;1470847;85294394
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;2;64;2413120;144802560;2413245;139975924
1;2;64;2415296;144913920;2415356;140098188
2;2;64;2416768;144898560;2416573;140105670
3;2;64;2418176;145056000;2418110;140261806
4;2;64;2416512;144990720;2416509;140172950
5;2;64;2415168;144860160;2414466;140064780
6;2;64;2416960;144983040;2416833;140190930
7;2;64;2413632;144768000;2413568;140001734
8;2;64;2415296;144898560;2414589;140087168
9;2;64;2416576;144963840;2416892;140190930
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;3;64;3419008;205155840;3418882;198239244
1;3;64;3428032;205585920;3427971;198744234
2;3;64;3425472;205536000;3425344;198677260
3;3;64;3425088;205470720;3425156;198603136
4;3;64;3427648;205693440;3426883;198773888
5;3;64;3426880;205670400;3427392;198796044
6;3;64;3429120;205678080;3430140;198848186
7;3;64;3422976;205355520;3423490;198458136
8;3;64;3423168;205336320;3423486;198495372
9;3;64;3424384;205493760;3425538;198617868
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;4;64;4406464;264364800;4405244;255560296
1;4;64;4404672;264349440;4405122;255541504
2;4;64;4402368;264049920;4403326;255188864
3;4;64;4401344;264076800;4400702;255207134
4;4;64;4385536;263074560;4386620;254312716
5;4;64;4386560;263189760;4385404;254379532
6;4;64;4398784;263857920;4399031;255025288
7;4;64;4407232;264445440;4407998;255637900
8;4;64;4413184;264698880;4413758;255875816
9;4;64;4411328;264526080;4411906;255712372
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;5;64;5094464;305871360;5094464;295657262
1;5;64;5090816;305514240;5091201;295274810
2;5;64;5088384;305387520;5089792;295175108
3;5;64;5079296;304869120;5079484;294680368
4;5;64;5092992;305544960;5094207;295349166
5;5;64;5092416;305502720;5093372;295334260
6;5;64;5080896;304896000;5081090;294677004
7;5;64;5085376;305114880;5086401;294933058
8;5;64;5092544;305575680;5092036;295356938
9;5;64;5093056;305652480;5093832;295449506
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;6;64;5705088;342351360;5705784;330965110
1;6;64;5710272;342743040;5707591;331373952
2;6;64;5703424;342182400;5701826;330776552
3;6;64;5708736;342604800;5707963;331147462
4;6;64;5710144;342654720;5712067;331202910
5;6;64;5712064;342777600;5711361;331292288
6;6;64;5710144;342585600;5708607;331144272
7;6;64;5699840;342021120;5697853;330609222
8;6;64;5701184;342124800;5702909;330653592
9;6;64;5711360;342735360;5713283;331247686
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;7;64;6244416;374603520;6243591;362180072
1;7;64;6230912;374016000;6231490;361534126
2;7;64;6244800;374776320;6244866;362224326
3;7;64;6238720;374376960;6238261;361838510
4;7;64;6218816;373079040;6220413;360683962
5;7;64;6224320;373566720;6225086;361017404
6;7;64;6224000;373570560;6221370;360936088
7;7;64;6210048;372741120;6210627;360212654
8;7;64;6231616;374035200;6231537;361445502
9;7;64;6227840;373724160;6228802;361162752
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;8;64;6251840;375144960;6251849;362609678
1;8;64;6250816;375014400;6250881;362547038
2;8;64;6257728;375432960;6257160;362911104
3;8;64;6255552;375325440;6255622;362822074
4;8;64;6243776;374576640;6243270;362120622
5;8;64;6237184;374296320;6237690;361790080
6;8;64;6240960;374415360;6240714;361927366
7;8;64;6222784;373317120;6223746;360854424
8;8;64;6225920;373593600;6227014;361154980
9;8;64;6238528;374304000;6237701;361845238
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;14;64;6486144;389184000;6486135;376236488
1;14;64;6454912;387390720;6454222;374466734
2;14;64;6441152;386480640;6440431;373572780
3;14;64;6450240;386972160;6450870;374070014
4;14;64;6465600;387997440;6467221;375089654
5;14;64;6448384;386860800;6448000;373980230
6;14;64;6452352;387095040;6452148;374168904
7;14;64;6441984;386507520;6443203;373665058
8;14;64;6456704;387340800;6455744;374429092
9;14;64;6464640;387901440;6465218;374949004
ID;CPU_CORES / RSS QUEUES;PKT_SIZE;PPS_RX;BPS_RX;PPS_TX;BPS_TX
0;16;64;6939008;416325120;6938696;402411192
1;16;64;6941952;416444160;6941745;402558918
2;16;64;6960576;417584640;6960707;403698718
3;16;64;6940736;416486400;6941820;402503876
4;16;64;6927680;415741440;6927420;401853870
5;16;64;6929792;415687680;6929917;401839196
6;16;64;6950400;416989440;6950661;403026166
7;16;64;6953664;417216000;6953454;403260544
8;16;64;6948480;416851200;6948800;403023266
9;16;64;6924160;415422720;6924092;401542468
^ permalink raw reply
* [PATCH net] udp: harden copy_linear_skb()
From: Eric Dumazet @ 2017-08-11 17:48 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Paolo Abeni
From: Eric Dumazet <edumazet@google.com>
syzkaller got crashes with CONFIG_HARDENED_USERCOPY=y configs.
Issue here is that recvfrom() can be used with user buffer of Z bytes,
and SO_PEEK_OFF of X bytes, from a skb with Y bytes, and following
condition :
Z < X < Y
kernel BUG at mm/usercopy.c:72!
invalid opcode: 0000 [#1] SMP KASAN
Dumping ftrace buffer:
(ftrace buffer empty)
Modules linked in:
CPU: 0 PID: 2917 Comm: syzkaller842281 Not tainted 4.13.0-rc3+ #16
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
Google 01/01/2011
task: ffff8801d2fa40c0 task.stack: ffff8801d1fe8000
RIP: 0010:report_usercopy mm/usercopy.c:64 [inline]
RIP: 0010:__check_object_size+0x3ad/0x500 mm/usercopy.c:264
RSP: 0018:ffff8801d1fef8a8 EFLAGS: 00010286
RAX: 0000000000000078 RBX: ffffffff847102c0 RCX: 0000000000000000
RDX: 0000000000000078 RSI: 1ffff1003a3fded5 RDI: ffffed003a3fdf09
RBP: ffff8801d1fef998 R08: 0000000000000001 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: ffff8801d1ea480e
R13: fffffffffffffffa R14: ffffffff84710280 R15: dffffc0000000000
FS: 0000000001360880(0000) GS:ffff8801dc000000(0000)
knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000202ecfe4 CR3: 00000001d1ff8000 CR4: 00000000001406f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
check_object_size include/linux/thread_info.h:108 [inline]
check_copy_size include/linux/thread_info.h:139 [inline]
copy_to_iter include/linux/uio.h:105 [inline]
copy_linear_skb include/net/udp.h:371 [inline]
udpv6_recvmsg+0x1040/0x1af0 net/ipv6/udp.c:395
inet_recvmsg+0x14c/0x5f0 net/ipv4/af_inet.c:793
sock_recvmsg_nosec net/socket.c:792 [inline]
sock_recvmsg+0xc9/0x110 net/socket.c:799
SYSC_recvfrom+0x2d6/0x570 net/socket.c:1788
SyS_recvfrom+0x40/0x50 net/socket.c:1760
entry_SYSCALL_64_fastpath+0x1f/0xbe
Fixes: b65ac44674dd ("udp: try to avoid 2 cache miss on dequeue")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Paolo Abeni <pabeni@redhat.com>
---
include/net/udp.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/net/udp.h b/include/net/udp.h
index cc8036987dcb..e9b1d1eacb59 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -368,6 +368,8 @@ static inline int copy_linear_skb(struct sk_buff *skb, int len, int off,
{
int n, copy = len - off;
+ if (copy < 0)
+ return -EINVAL;
n = copy_to_iter(skb->data + off, copy, to);
if (n == copy)
return 0;
^ permalink raw reply related
* Re: [PATCH net-next] net: skb_needs_check() removes CHECKSUM_UNNECESSARY check for tx.
From: Willem de Bruijn @ 2017-08-11 17:43 UTC (permalink / raw)
To: Tonghao Zhang; +Cc: Network Development, Willem de Bruijn
In-Reply-To: <1502421389-20152-1-git-send-email-xiangxia.m.yue@gmail.com>
On Thu, Aug 10, 2017 at 8:16 PM, Tonghao Zhang <xiangxia.m.yue@gmail.com> wrote:
> Because we remove the UFO support, we will also remove the
> CHECKSUM_UNNECESSARY check in skb_needs_check().
>
> Cc: Willem de Bruijn <willemb@google.com>
> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Thanks for fixing up and resubmitting after the merge.
^ permalink raw reply
* Re: [PATCH] netfilter: nf_nat_h323: fix logical-not-parentheses warning
From: Pablo Neira Ayuso @ 2017-08-11 17:42 UTC (permalink / raw)
To: Nick Desaulniers
Cc: mka, lorenzo, Jozsef Kadlecsik, Florian Westphal, David S. Miller,
Alexey Kuznetsov, Hideaki YOSHIFUJI, netfilter-devel, coreteam,
netdev, linux-kernel
In-Reply-To: <20170731183949.73763-1-ndesaulniers@google.com>
Hi Nick,
On Mon, Jul 31, 2017 at 11:39:49AM -0700, Nick Desaulniers wrote:
> Clang produces the following warning:
[...]
> Also, it's even cleaner to use the form:
>
> if (x)
>
> but then if the return codes change from treating 0 as success (unlikely),
> then all call sites must be updated.
>
> I'm happy to send v2 that changes to that form, and updates the other call
> sites to be:
>
> if (set_h225_addr())
> handle_failures()
> else
> handle_success()
That sounds very reasonable, send a v2 if this triggers a larger
patch.
Or I can just take this patch, as you prefer.
Thanks!
^ permalink raw reply
* Re: [PATCH net-next v2] vxlan: change vxlan_[config_]validate() to use netlink_ext_ack for error reporting
From: Jiri Benc @ 2017-08-11 17:28 UTC (permalink / raw)
To: David Ahern
Cc: Roopa Prabhu, Girish Moodalbail, pravin shelar,
davem@davemloft.net, netdev@vger.kernel.org, Matthias Schiffer
In-Reply-To: <0af5e8f9-36cf-8aed-b431-ffc19eac4c8f@gmail.com>
On Fri, 11 Aug 2017 11:17:54 -0600, David Ahern wrote:
> What if a user adds IFLA_INFO_DATA but adds no vxlan attributes under
> it? Still not a valid config, but it passes the !data check.
Part of the checking is done in the newlink callback (vxlan_nl2conf).
Not nice but that's how it is. It's out of scope of this patch to
change that. (It's also not easy - most of the newlink logic would have
to be repeated in validate.)
The !data check needs to be done prior to blindly dereferencing into
data. It's currently in the validate callback. A bit chaotic but it
works. This patch just adds error messages.
> Whatever attributes are required but missing should be the message
> returned.
See the message I proposed in the previous email. newlink will take
care of the rest.
Feel free to submit cleanups, the vxlan driver could use them.
Jiri
^ permalink raw reply
* Re: unregister_netdevice: waiting for eth0 to become free. Usage count = 1
From: Wei Wang @ 2017-08-11 17:25 UTC (permalink / raw)
To: Cong Wang, John Stultz
Cc: lkml, Network Development, Linux USB List, David S. Miller,
Felipe Balbi, Martin KaFai Lau
In-Reply-To: <CAM_iQpWMWg5ytDq2Y9p9uet1zowGuCX+eksyiyxu9vQ18WoPxQ@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1553 bytes --]
On Fri, Aug 11, 2017 at 9:48 AM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> Hi,
>
> On Thu, Aug 10, 2017 at 11:12 AM, John Stultz <john.stultz@linaro.org> wrote:
>> On Wed, Aug 9, 2017 at 10:41 PM, Wei Wang <weiwan@google.com> wrote:
>>> Hi John,
>>>
>>> Is it possible to try the attached patch?
>>
>> Thanks so much for the quick turn around!
>>
>> So I dropped all the reverts you suggested, and applied this one
>> against 4.13-rc4, but I'm still seeing the problematic behavior.
>
> Does the following one-line fix make a difference?
>
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index a640fbcba15d..c145a35763a0 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -141,7 +141,7 @@ static void rt6_uncached_list_del(struct rt6_info *rt)
> struct uncached_list *ul = rt->rt6i_uncached_list;
>
> spin_lock_bh(&ul->lock);
> - list_del(&rt->rt6i_uncached);
> + list_del_init(&rt->rt6i_uncached);
> spin_unlock_bh(&ul->lock);
> }
> }
Thanks a lot Cong for proposing this fix.
For the last few days, John has been helping me running debug image
and we found out that the leaked dst is probably in addrconf.c.
Martin and I are looking through the code and trying to put more debugs.
John,
If after Cong's fix, the issue still happens, could you help try the
patch attached and collect all logs when you try the reproduce the
issue? It would be great to have logs for both success case and the
failure case.
Thanks so much for your help.
Wei
[-- Attachment #2: 0001-ipv6-unregister_netdevice-debug.patch --]
[-- Type: text/x-patch, Size: 13057 bytes --]
From 0ff591e00eac13888c5ee9c84ee51b286b27389d Mon Sep 17 00:00:00 2001
From: Wei Wang <weiwan@google.com>
Date: Thu, 10 Aug 2017 21:12:32 -0700
Subject: [PATCH] ipv6: unregister_netdevice debug
Change-Id: I97b044b957a146de480e5427212c1ce80bc3dd3c
---
include/net/dst.h | 7 +++++++
include/net/dst_ops.h | 1 +
include/net/ip6_fib.h | 10 ++++++++++
net/core/dev.c | 16 +++++++++++++++
net/core/dst.c | 10 ++++++++--
net/ipv6/addrconf.c | 24 +++++++++++++++++++---
net/ipv6/route.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++---
7 files changed, 115 insertions(+), 8 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index f73611ec4017..48d9f0322492 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -56,6 +56,13 @@ struct dst_entry {
#define DST_XFRM_TUNNEL 0x0020
#define DST_XFRM_QUEUE 0x0040
#define DST_METADATA 0x0080
+#define RTF_ICMPV6_DST 0x0100
+#define RTF_ADDRCONF_DST 0x0200
+#define RTF_UNCACHED_DST 0x0400
+#define RTF_CACHE_DST 0x0800
+#define RTF_FIB6_DST 0x1000
+#define RTF_PCPU_DST 0x2000
+
short error;
diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h
index c84b3287e38b..eef7d6b6f3cd 100644
--- a/include/net/dst_ops.h
+++ b/include/net/dst_ops.h
@@ -39,6 +39,7 @@ struct dst_ops {
struct kmem_cache *kmem_cachep;
struct percpu_counter pcpuc_entries ____cacheline_aligned_in_smp;
+ void (*do_account)(struct dst_entry *dst);
};
static inline int dst_entries_get_fast(struct dst_ops *dst)
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 1a88008cc6f5..af382d123f63 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -214,6 +214,16 @@ struct rt6_statistics {
__u32 fib_rt_entries; /* rt entries in table */
__u32 fib_rt_cache; /* cache routes */
__u32 fib_discarded_routes;
+ __u32 icmpv6_dst;
+ __u32 addrconf_dst;
+ __u32 fib6_dst;
+ __u32 cache_dst;
+ __u32 uncached_dst;
+ __u32 pcpu_dst;
+ __u32 dev_free_fib6;
+ __u32 dev_free_uncached;
+ __u32 dev_free_icmpv6;
+ __u32 dev_free_addrconf;
};
#define RTN_TL_ROOT 0x0001
diff --git a/net/core/dev.c b/net/core/dev.c
index 8ea6b4b42611..5c6fea78003f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1,3 +1,4 @@
+
/*
* NET3 Protocol independent device support routines.
*
@@ -7738,8 +7739,23 @@ static void netdev_wait_allrefs(struct net_device *dev)
{
unsigned long rebroadcast_time, warning_time;
int refcnt;
+ struct net *net = dev_net(dev);
linkwatch_forget_dev(dev);
+ printk("%s: dev_name %s, icmpv6_dst %u, addrconf_dst %u, fib6_dst %u, pcpu_dst %u, cache_dst %u, uncached_list %u, dev_free_fib6 %u, dev_free_uncached %u, dev_free_icmpv6 %u, dev_free_addrconf %u, fib_rt_entries %u\n", __func__,
+ dev->name,
+ net->ipv6.rt6_stats->icmpv6_dst,
+ net->ipv6.rt6_stats->addrconf_dst,
+ net->ipv6.rt6_stats->fib6_dst,
+ net->ipv6.rt6_stats->pcpu_dst,
+ net->ipv6.rt6_stats->cache_dst,
+ net->ipv6.rt6_stats->uncached_dst,
+ net->ipv6.rt6_stats->dev_free_fib6,
+ net->ipv6.rt6_stats->dev_free_uncached,
+ net->ipv6.rt6_stats->dev_free_icmpv6,
+ net->ipv6.rt6_stats->dev_free_addrconf,
+ net->ipv6.rt6_stats->fib_rt_entries);
+
rebroadcast_time = warning_time = jiffies;
refcnt = netdev_refcnt_read(dev);
diff --git a/net/core/dst.c b/net/core/dst.c
index 00aa972ad1a1..8c20deec398b 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -184,8 +184,11 @@ void dst_release(struct dst_entry *dst)
if (unlikely(newrefcnt < 0))
net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
__func__, dst, newrefcnt);
- if (!newrefcnt)
+ if (!newrefcnt) {
call_rcu(&dst->rcu_head, dst_destroy_rcu);
+ if(dst->ops->do_account)
+ dst->ops->do_account(dst);
+ }
}
}
EXPORT_SYMBOL(dst_release);
@@ -199,8 +202,11 @@ void dst_release_immediate(struct dst_entry *dst)
if (unlikely(newrefcnt < 0))
net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
__func__, dst, newrefcnt);
- if (!newrefcnt)
+ if (!newrefcnt) {
dst_destroy(dst);
+ if(dst->ops->do_account)
+ dst->ops->do_account(dst);
+ }
}
}
EXPORT_SYMBOL(dst_release_immediate);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3c46e9513a31..4625425378ae 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -95,7 +95,7 @@
#include <linux/export.h>
/* Set to 3 to get tracing... */
-#define ACONF_DEBUG 2
+#define ACONF_DEBUG 3
#if ACONF_DEBUG >= 3
#define ADBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
@@ -108,6 +108,8 @@
#define IPV6_MAX_STRLEN \
sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
+static int num_ifa;
+
static inline u32 cstamp_delta(unsigned long cstamp)
{
return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
@@ -923,9 +925,11 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
pr_warn("Freeing alive inet6 address %p\n", ifp);
return;
}
+ printk("%s: dst refcnt %d", __func__, atomic_read(&(ifp->rt->dst.__refcnt)));
ip6_rt_put(ifp->rt);
kfree_rcu(ifp, rcu);
+ num_ifa--;
}
static void
@@ -1016,6 +1020,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
goto out;
}
+ num_ifa++;
+
rt = addrconf_dst_alloc(idev, addr, false);
if (IS_ERR(rt)) {
err = PTR_ERR(rt);
@@ -1076,6 +1082,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
inet6addr_notifier_call_chain(NETDEV_UP, ifa);
else {
kfree(ifa);
+ num_ifa--;
in6_dev_put(idev);
ifa = ERR_PTR(err);
}
@@ -3598,6 +3605,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
int _keep_addr;
bool keep_addr;
int state, i;
+ int err;
ASSERT_RTNL();
@@ -3679,12 +3687,14 @@ static int addrconf_ifdown(struct net_device *dev, int how)
spin_unlock_bh(&ifa->lock);
in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
+ printk("%s: release idev->tempaddr_list entries\n", __func__);
}
/* re-combine the user config with event to determine if permanent
* addresses are to be removed from the interface list
*/
keep_addr = (!how && _keep_addr > 0 && !idev->cnf.disable_ipv6);
+ printk("%s: num_ifa %d\n", __func__, num_ifa);
INIT_LIST_HEAD(&del_list);
list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) {
@@ -3710,15 +3720,20 @@ static int addrconf_ifdown(struct net_device *dev, int how)
rt = ifa->rt;
ifa->rt = NULL;
+ printk("%s: keep ifa\n", __func__);
} else {
state = ifa->state;
ifa->state = INET6_IFADDR_STATE_DEAD;
+ printk("%s: not keep ifa\n", __func__);
}
spin_unlock_bh(&ifa->lock);
- if (rt)
- ip6_del_rt(rt);
+ if (rt) {
+ err = ip6_del_rt(rt);
+ if (err)
+ printk("%s: ip6_del_rt() failed\n", __func__);
+ }
if (state != INET6_IFADDR_STATE_DEAD) {
__ipv6_ifa_notify(RTM_DELADDR, ifa);
@@ -3741,7 +3756,9 @@ static int addrconf_ifdown(struct net_device *dev, int how)
list_del(&ifa->if_list);
in6_ifa_put(ifa);
+ printk("%s: delete ifa from del_list\n", __func__);
}
+ printk("%s: num_ifa %d\n", __func__, num_ifa);
/* Step 5: Discard anycast and multicast list */
if (how) {
@@ -6566,6 +6583,7 @@ int __init addrconf_init(void)
err = -ENOMEM;
goto out_nowq;
}
+ num_ifa = 0;
/* The addrconf netdev notifier requires that loopback_dev
* has it's ipv6 private information allocated and setup
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 4d30c96a819d..422c39d8cc44 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -172,6 +172,10 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
rt->dst.dev = loopback_dev;
dev_hold(rt->dst.dev);
dev_put(rt_dev);
+ if (rt->dst.flags | RTF_ICMPV6_DST)
+ net->ipv6.rt6_stats->dev_free_icmpv6++;
+ else
+ net->ipv6.rt6_stats->dev_free_uncached++;
}
}
spin_unlock_bh(&ul->lock);
@@ -237,6 +241,25 @@ static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
__ipv6_confirm_neigh(dev, daddr);
}
+static void ip6_do_account(struct dst_entry *dst)
+{
+ struct net_device *dev = dst->dev;
+ struct net *net = dev_net(dev);
+
+ if (dst->flags & RTF_ICMPV6_DST)
+ net->ipv6.rt6_stats->icmpv6_dst--;
+ if (dst->flags & RTF_ADDRCONF_DST)
+ net->ipv6.rt6_stats->addrconf_dst--;
+ if (dst->flags & RTF_FIB6_DST)
+ net->ipv6.rt6_stats->fib6_dst--;
+ if (dst->flags & RTF_UNCACHED_DST)
+ net->ipv6.rt6_stats->uncached_dst--;
+ if (dst->flags & RTF_CACHE_DST)
+ net->ipv6.rt6_stats->cache_dst--;
+ if (dst->flags & RTF_PCPU_DST)
+ net->ipv6.rt6_stats->pcpu_dst--;
+}
+
static struct dst_ops ip6_dst_ops_template = {
.family = AF_INET6,
.gc = ip6_dst_gc,
@@ -254,6 +277,7 @@ static struct dst_ops ip6_dst_ops_template = {
.local_out = __ip6_local_out,
.neigh_lookup = ip6_neigh_lookup,
.confirm_neigh = ip6_confirm_neigh,
+ .do_account = ip6_do_account,
};
static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
@@ -1004,6 +1028,7 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
{
struct rt6_info *pcpu_rt;
+ struct net *net = dev_net(rt->dst.dev);
pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
rt->dst.dev, rt->dst.flags);
@@ -1013,6 +1038,9 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
ip6_rt_copy_init(pcpu_rt, rt);
pcpu_rt->rt6i_protocol = rt->rt6i_protocol;
pcpu_rt->rt6i_flags |= RTF_PCPU;
+ pcpu_rt->dst.flags &= ~(RTF_CACHE_DST|RTF_ADDRCONF_DST|RTF_FIB6_DST);
+ pcpu_rt->dst.flags |= RTF_PCPU_DST;
+ net->ipv6.rt6_stats->pcpu_dst++;
return pcpu_rt;
}
@@ -1135,6 +1163,8 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
* No need for another dst_hold()
*/
rt6_uncached_list_add(uncached_rt);
+ net->ipv6.rt6_stats->uncached_dst++;
+ uncached_rt->dst.flags |= RTF_UNCACHED_DST;
} else {
uncached_rt = net->ipv6.ip6_null_entry;
dst_hold(&uncached_rt->dst);
@@ -1415,6 +1445,9 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
if (nrt6) {
+ struct net *net = dev_net(nrt6->dst.dev);
+ net->ipv6.rt6_stats->cache_dst++;
+ nrt6->dst.flags |= RTF_CACHE_DST;
rt6_do_update_pmtu(nrt6, mtu);
/* ip6_ins_rt(nrt6) will bump the
@@ -1673,7 +1706,8 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
goto out;
}
- rt->dst.flags |= DST_HOST;
+ rt->dst.flags |= (DST_HOST|RTF_ICMPV6_DST);
+ net->ipv6.rt6_stats->icmpv6_dst++;
rt->dst.output = ip6_output;
rt->rt6i_gateway = fl6->daddr;
rt->rt6i_dst.addr = fl6->daddr;
@@ -1870,6 +1904,9 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
err = -ENOMEM;
goto out;
}
+ rt->dst.flags |= RTF_FIB6_DST;
+ net->ipv6.rt6_stats->fib6_dst++;
+
if (cfg->fc_flags & RTF_EXPIRES)
rt6_set_expires(rt, jiffies +
@@ -2265,6 +2302,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
struct rd_msg *msg;
int optlen, on_link;
u8 *lladdr;
+ struct net *net;
optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
optlen -= sizeof(*msg);
@@ -2352,6 +2390,9 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
nrt->rt6i_flags &= ~RTF_GATEWAY;
nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
+ net = dev_net(nrt->dst.dev);
+ net->ipv6.rt6_stats->cache_dst++;
+ nrt->dst.flags |= RTF_CACHE_DST;
if (ip6_ins_rt(nrt))
goto out_release;
@@ -2703,7 +2744,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
in6_dev_hold(idev);
- rt->dst.flags |= DST_HOST;
+ rt->dst.flags |= (DST_HOST|RTF_ADDRCONF_DST);
rt->dst.input = ip6_input;
rt->dst.output = ip6_output;
rt->rt6i_idev = idev;
@@ -2720,6 +2761,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
rt->rt6i_dst.plen = 128;
tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
rt->rt6i_table = fib6_get_table(net, tb_id);
+ net->ipv6.rt6_stats->addrconf_dst++;
return rt;
}
@@ -2757,6 +2799,7 @@ void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
fib6_clean_all(net, fib6_remove_prefsrc, &adni);
}
+
#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY)
#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE)
@@ -2788,13 +2831,19 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg)
{
const struct arg_dev_net *adn = arg;
const struct net_device *dev = adn->dev;
+ struct net *net = dev_net(dev);
if ((rt->dst.dev == dev || !dev) &&
rt != adn->net->ipv6.ip6_null_entry &&
(rt->rt6i_nsiblings == 0 ||
(dev && netdev_unregistering(dev)) ||
- !rt->rt6i_idev->cnf.ignore_routes_with_linkdown))
+ !rt->rt6i_idev->cnf.ignore_routes_with_linkdown)) {
+ if (rt->dst.flags | RTF_ADDRCONF_DST)
+ net->ipv6.rt6_stats->dev_free_addrconf++;
+ else
+ net->ipv6.rt6_stats->dev_free_fib6++;
return -1;
+ }
return 0;
}
--
2.14.0.434.g98096fd7a8-goog
^ permalink raw reply related
* Re: [PATCH net-next v2] vxlan: change vxlan_[config_]validate() to use netlink_ext_ack for error reporting
From: Girish Moodalbail @ 2017-08-11 17:21 UTC (permalink / raw)
To: Jiri Benc, Roopa Prabhu
Cc: pravin shelar, davem@davemloft.net, netdev@vger.kernel.org,
Matthias Schiffer
In-Reply-To: <20170811183957.47f418e6@griffin>
[snip]
>>> @@ -2933,6 +2945,8 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf,
>>> */
>>> if ((conf->flags & ~VXLAN_F_ALLOWED_GPE) ||
>>> !(conf->flags & VXLAN_F_COLLECT_METADATA)) {
>>> + NL_SET_ERR_MSG(extack,
>>> + "VXLAN GPE does not support this combination of attributes");
>>> return -EINVAL;
>>> }
>>
>> "collect metadata not supported with vxlan gpe"
Actually, VXLAN GPE is only supported together with external keyword. From
ip-link(8)...
gpe - enables the Generic Protocol extension (VXLAN-GPE). Currently, this
is only supported together with the external keyword.
> That's completely wrong message. Not saying that the capitalization is
> wrong, too. Girish's wording precisely explains what went wrong.
Furthermore, the condition not only checks for collect metadata but also it
checks to see if any attribute specified is outside of what is allowed by
VXLAN_F_ALLOWED_GPE.
>
>>> lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
>>> - if (!lowerdev)
>>> + if (!lowerdev) {
>>> + NL_SET_ERR_MSG(extack,
>>> + "Specified interface for tunnel endpoint communications not found");
>>> return -ENODEV;
>>
>> "invalid vxlan remote link interface, device not found"
>
> Finally one that looks better :-) Modulo the missing capitalization,
> though.
It is not the remote link interface. It is the local interface itself that needs
to be specified.
>
>>> - if (vxlan_addr_multicast(&conf->remote_ip))
>>> + if (vxlan_addr_multicast(&conf->remote_ip)) {
>>> + NL_SET_ERR_MSG(extack,
>>> + "Interface need to be specified for multicast destination");
>>
>> "vxlan remote link interface required for multicast remote destination"
>
> I like this one better, too.
>
>>> #if IS_ENABLED(CONFIG_IPV6)
>>> - if (conf->flags & VXLAN_F_IPV6_LINKLOCAL)
>>> + if (conf->flags & VXLAN_F_IPV6_LINKLOCAL) {
>>> + NL_SET_ERR_MSG(extack,
>>> + "Interface need to be specified for link-local local/remote addresses");
>>> return -EINVAL;
>>
>> "vxlan link interface required for link-local local/remote addresses"
>
> Okay but to be consistent (and more clear), it should be "remote link
> interface".
There is no remote link while configuring VXLAN. It is the local interface
through which VXLAN packets will be send out.
Thanks all for the review,
~Girish
^ permalink raw reply
* Re: [PATCH net-next v2] vxlan: change vxlan_[config_]validate() to use netlink_ext_ack for error reporting
From: David Ahern @ 2017-08-11 17:17 UTC (permalink / raw)
To: Jiri Benc
Cc: Roopa Prabhu, Girish Moodalbail, pravin shelar,
davem@davemloft.net, netdev@vger.kernel.org, Matthias Schiffer
In-Reply-To: <20170811191155.4906360a@griffin>
On 8/11/17 11:11 AM, Jiri Benc wrote:
> On Fri, 11 Aug 2017 10:56:57 -0600, David Ahern wrote:
>> I would argue none of those messages are sufficient. The message should
>> tell the user what is missing.
>
> Good point.
>
> I guess "The IFLA_INFO_DATA attribute is missing" would be a better
> message. It can happen only when you're implementing your own
> management tool, it's not that you'll get this message out of the ip
> tool, thus referring to netlink attributes should be okay.
>
>> What is the point of the !data check anyway? Based on the rest of the
>> validate function neither IFLA_VXLAN_ID or IFLA_VXLAN_PORT_RANGE are
>> required attributes.
>
> The newlink callback assumes data is not NULL, i.e. IFLA_INFO_DATA is
> present. It would crash otherwise.
What if a user adds IFLA_INFO_DATA but adds no vxlan attributes under
it? Still not a valid config, but it passes the !data check.
Whatever attributes are required but missing should be the message
returned.
^ permalink raw reply
* Re: [PATCH net-next v2] vxlan: change vxlan_[config_]validate() to use netlink_ext_ack for error reporting
From: Jiri Benc @ 2017-08-11 17:11 UTC (permalink / raw)
To: David Ahern
Cc: Roopa Prabhu, Girish Moodalbail, pravin shelar,
davem@davemloft.net, netdev@vger.kernel.org, Matthias Schiffer
In-Reply-To: <62ddb5a5-2242-abea-7702-fbf7377d8a1e@gmail.com>
On Fri, 11 Aug 2017 10:56:57 -0600, David Ahern wrote:
> I would argue none of those messages are sufficient. The message should
> tell the user what is missing.
Good point.
I guess "The IFLA_INFO_DATA attribute is missing" would be a better
message. It can happen only when you're implementing your own
management tool, it's not that you'll get this message out of the ip
tool, thus referring to netlink attributes should be okay.
> What is the point of the !data check anyway? Based on the rest of the
> validate function neither IFLA_VXLAN_ID or IFLA_VXLAN_PORT_RANGE are
> required attributes.
The newlink callback assumes data is not NULL, i.e. IFLA_INFO_DATA is
present. It would crash otherwise.
Jiri
^ permalink raw reply
* Re: [PATCH net-next 00/14] sctp: remove typedefs from structures part 6
From: David Miller @ 2017-08-11 17:03 UTC (permalink / raw)
To: lucien.xin; +Cc: netdev, linux-sctp, marcelo.leitner, nhorman
In-Reply-To: <cover.1502417340.git.lucien.xin@gmail.com>
From: Xin Long <lucien.xin@gmail.com>
Date: Fri, 11 Aug 2017 10:23:44 +0800
> As we know, typedef is suggested not to use in kernel, even checkpatch.pl
> also gives warnings about it. Now sctp is using it for many structures.
>
> All this kind of typedef's using should be removed. This patchset is the
> part 6 to remove all typedefs in include/net/sctp/structs.h, command.h
> and sm.h.
>
> Just as the part 1-5, No any code's logic would be changed in these patches,
> only cleaning up.
>
> Note that this is the last part for this typedef cleaning up. after this
> patchset, no more inappropriate typedefs in sctp. It's also to tidy some
> codes when removing them, like fixing many indents, reodering some local
> params, especially in the last 2 patches.
Series applied, thanks Xin.
^ permalink raw reply
* Re: [PATCH net-next v2] vxlan: change vxlan_[config_]validate() to use netlink_ext_ack for error reporting
From: David Ahern @ 2017-08-11 16:56 UTC (permalink / raw)
To: Jiri Benc, Roopa Prabhu
Cc: Girish Moodalbail, pravin shelar, davem@davemloft.net,
netdev@vger.kernel.org, Matthias Schiffer
In-Reply-To: <20170811183957.47f418e6@griffin>
On 8/11/17 10:39 AM, Jiri Benc wrote:
>>> + if (!data) {
>>> + NL_SET_ERR_MSG(extack,
>>> + "Not enough attributes provided to perform the operation");
>>> return -EINVAL;
>>> + }
>> "not enough attributes"
> You're missing part of the sentence.
>
I would argue none of those messages are sufficient. The message should
tell the user what is missing.
What is the point of the !data check anyway? Based on the rest of the
validate function neither IFLA_VXLAN_ID or IFLA_VXLAN_PORT_RANGE are
required attributes.
^ permalink raw reply
* Re: unregister_netdevice: waiting for eth0 to become free. Usage count = 1
From: Cong Wang @ 2017-08-11 16:48 UTC (permalink / raw)
To: John Stultz
Cc: Wei Wang, lkml, Network Development, Linux USB List,
David S. Miller, Felipe Balbi
In-Reply-To: <CALAqxLUoV6EQvofTEv9whW1_QMPBPU7eJBhRFUjaSs7CGeRFww@mail.gmail.com>
Hi,
On Thu, Aug 10, 2017 at 11:12 AM, John Stultz <john.stultz@linaro.org> wrote:
> On Wed, Aug 9, 2017 at 10:41 PM, Wei Wang <weiwan@google.com> wrote:
>> Hi John,
>>
>> Is it possible to try the attached patch?
>
> Thanks so much for the quick turn around!
>
> So I dropped all the reverts you suggested, and applied this one
> against 4.13-rc4, but I'm still seeing the problematic behavior.
Does the following one-line fix make a difference?
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a640fbcba15d..c145a35763a0 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -141,7 +141,7 @@ static void rt6_uncached_list_del(struct rt6_info *rt)
struct uncached_list *ul = rt->rt6i_uncached_list;
spin_lock_bh(&ul->lock);
- list_del(&rt->rt6i_uncached);
+ list_del_init(&rt->rt6i_uncached);
spin_unlock_bh(&ul->lock);
}
}
^ permalink raw reply related
* Re: [RFC PATCH 2/2] bpf: Initialise mod[] in bpf_trace_printk
From: Daniel Borkmann @ 2017-08-11 16:47 UTC (permalink / raw)
To: James Hogan, David Miller; +Cc: ast, linux-kernel, rostedt, mingo, netdev
In-Reply-To: <598B71C9.7090303@iogearbox.net>
Hi James,
On 08/09/2017 10:34 PM, Daniel Borkmann wrote:
> On 08/09/2017 09:39 AM, James Hogan wrote:
> [...]
>> time (but please consider looking at the other patch which is certainly
>> a more real issue).
>
> Sorry for the delay, started looking into that and whether we
> have some other options, I'll get back to you on this.
Could we solve this more generically (as in: originally intended) in
the sense that we don't need to trust the gcc va_list handling; I feel
this is relying on an implementation detail? Perhaps something like
below poc patch?
Thanks again,
Daniel
From 71f16544d455abb6bb82f7253c17c14d2a395e91 Mon Sep 17 00:00:00 2001
Message-Id: <71f16544d455abb6bb82f7253c17c14d2a395e91.1502469361.git.daniel@iogearbox.net>
From: Daniel Borkmann <daniel@iogearbox.net>
Date: Fri, 11 Aug 2017 15:56:32 +0200
Subject: [PATCH] bpf: fix bpf_trace_printk on 32 bit
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
kernel/trace/bpf_trace.c | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 3738519..d4cb36f 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -204,10 +204,33 @@ static const struct bpf_func_proto *bpf_get_probe_write_proto(void)
fmt_cnt++;
}
- return __trace_printk(1/* fake ip will not be printed */, fmt,
- mod[0] == 2 ? arg1 : mod[0] == 1 ? (long) arg1 : (u32) arg1,
- mod[1] == 2 ? arg2 : mod[1] == 1 ? (long) arg2 : (u32) arg2,
- mod[2] == 2 ? arg3 : mod[2] == 1 ? (long) arg3 : (u32) arg3);
+#define __BPF_TP_EMIT() __BPF_ARG3_TP()
+#define __BPF_TP(...) \
+ __trace_printk(1 /* fake ip will not be printed */, \
+ fmt, ##__VA_ARGS__)
+
+#define __BPF_ARG1_TP(...) \
+ ((mod[0] == 2 || (mod[0] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_TP(arg1, ##__VA_ARGS__) \
+ : ((mod[0] == 1 || (mod[0] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_TP((long)arg1, ##__VA_ARGS__) \
+ : __BPF_TP((u32)arg1, ##__VA_ARGS__)))
+
+#define __BPF_ARG2_TP(...) \
+ ((mod[1] == 2 || (mod[1] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_ARG1_TP(arg2, ##__VA_ARGS__) \
+ : ((mod[1] == 1 || (mod[1] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_ARG1_TP((long)arg2, ##__VA_ARGS__) \
+ : __BPF_ARG1_TP((u32)arg2, ##__VA_ARGS__)))
+
+#define __BPF_ARG3_TP(...) \
+ ((mod[2] == 2 || (mod[2] == 1 && __BITS_PER_LONG == 64)) \
+ ? __BPF_ARG2_TP(arg3, ##__VA_ARGS__) \
+ : ((mod[2] == 1 || (mod[2] == 0 && __BITS_PER_LONG == 32)) \
+ ? __BPF_ARG2_TP((long)arg3, ##__VA_ARGS__) \
+ : __BPF_ARG2_TP((u32)arg3, ##__VA_ARGS__)))
+
+ return __BPF_TP_EMIT();
}
static const struct bpf_func_proto bpf_trace_printk_proto = {
--
1.9.3
^ permalink raw reply related
* Re: [PATCH net-next v2] vxlan: change vxlan_[config_]validate() to use netlink_ext_ack for error reporting
From: Jiri Benc @ 2017-08-11 16:39 UTC (permalink / raw)
To: Roopa Prabhu
Cc: Girish Moodalbail, pravin shelar, davem@davemloft.net,
netdev@vger.kernel.org, Matthias Schiffer
In-Reply-To: <CAJieiUjYggf3zNzwBMFq7zUm+RrZokZ7oNpuz-Hinec=0OSGzA@mail.gmail.com>
On Fri, 11 Aug 2017 09:19:34 -0700, Roopa Prabhu wrote:
> > if (tb[IFLA_ADDRESS]) {
> > if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
> > - pr_debug("invalid link address (not ethernet)\n");
> > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
> > + "Provided link layer address is not Ethernet");
> > return -EINVAL;
> > }
>
> keep it simple and closer to the original msg: "invalid link layer address"
I prefer more explanatory wording. Girish's is better.
> >
> > if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
> > - pr_debug("invalid all zero ethernet address\n");
> > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS],
> > + "Provided Ethernet address is not unicast");
> > return -EADDRNOTAVAIL;
>
> keep it simple and closer to the original msg: "invalid all zero
> ethernet address"
This would be incorrect message. The is_valid_ether_addr function does
not check only for all zeroes but also for !multicast. Girish's wording
better expresses what's going on.
> > + if (!data) {
> > + NL_SET_ERR_MSG(extack,
> > + "Not enough attributes provided to perform the operation");
> > return -EINVAL;
> > + }
>
> "not enough attributes"
You're missing part of the sentence.
> > if (data[IFLA_VXLAN_ID]) {
> > u32 id = nla_get_u32(data[IFLA_VXLAN_ID]);
> >
> > - if (id >= VXLAN_N_VID)
> > + if (id >= VXLAN_N_VID) {
> > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_ID],
> > + "VXLAN ID must be lower than 16777216");
> > return -ERANGE;
>
> "invalid vxlan-id"
This is exactly what I objected against in Girish's v1. It would be
useless to have extended error reporting but report things that don't
help users. I like the current Girish's wording, it's clear and helpful.
> > @@ -2761,8 +2772,8 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[],
> > = nla_data(data[IFLA_VXLAN_PORT_RANGE]);
> >
> > if (ntohs(p->high) < ntohs(p->low)) {
> > - pr_debug("port range %u .. %u not valid\n",
> > - ntohs(p->low), ntohs(p->high));
> > + NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_PORT_RANGE],
> > + "Provided source port range bounds is invalid");
> > return -EINVAL;
> > }
>
> "invalid source port range"
Could be. But please honor proper capitalization.
> > @@ -2933,6 +2945,8 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf,
> > */
> > if ((conf->flags & ~VXLAN_F_ALLOWED_GPE) ||
> > !(conf->flags & VXLAN_F_COLLECT_METADATA)) {
> > + NL_SET_ERR_MSG(extack,
> > + "VXLAN GPE does not support this combination of attributes");
> > return -EINVAL;
> > }
>
> "collect metadata not supported with vxlan gpe"
That's completely wrong message. Not saying that the capitalization is
wrong, too. Girish's wording precisely explains what went wrong.
> > - if (vxlan_addr_multicast(&conf->saddr))
> > + if (vxlan_addr_multicast(&conf->saddr)) {
> > + NL_SET_ERR_MSG(extack, "Local address cannot be multicast");
> > return -EINVAL;
>
> "invalid local address. multicast not supported"
Roopa, what happened to your shift key? And how is this better to what
Girish proposed?
> > + NL_SET_ERR_MSG(extack,
> > + "IPv6 support not enabled in the kernel");
>
> "invalid address family. ipv6 not enabled"
Ditto.
> > lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
> > - if (!lowerdev)
> > + if (!lowerdev) {
> > + NL_SET_ERR_MSG(extack,
> > + "Specified interface for tunnel endpoint communications not found");
> > return -ENODEV;
>
> "invalid vxlan remote link interface, device not found"
Finally one that looks better :-) Modulo the missing capitalization,
though.
> > - if (vxlan_addr_multicast(&conf->remote_ip))
> > + if (vxlan_addr_multicast(&conf->remote_ip)) {
> > + NL_SET_ERR_MSG(extack,
> > + "Interface need to be specified for multicast destination");
>
> "vxlan remote link interface required for multicast remote destination"
I like this one better, too.
> > #if IS_ENABLED(CONFIG_IPV6)
> > - if (conf->flags & VXLAN_F_IPV6_LINKLOCAL)
> > + if (conf->flags & VXLAN_F_IPV6_LINKLOCAL) {
> > + NL_SET_ERR_MSG(extack,
> > + "Interface need to be specified for link-local local/remote addresses");
> > return -EINVAL;
>
> "vxlan link interface required for link-local local/remote addresses"
Okay but to be consistent (and more clear), it should be "remote link
interface".
> > @@ -3038,6 +3082,7 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf,
> > tmp->cfg.remote_ifindex != conf->remote_ifindex)
> > continue;
> >
> > + NL_SET_ERR_MSG(extack, "Specified VNI is duplicate");
>
> "duplicate vni. vxlan device with vni exists."
What about "A VXLAN device with the specified VNI already exists."?
Jiri
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox