* [PATCH net-next v5 0/2] add UniPhier AVE ethernet support
From: Kunihiko Hayashi @ 2017-12-11 7:57 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA
Cc: Andrew Lunn, Florian Fainelli, Rob Herring, Mark Rutland,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Masahiro Yamada,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
This series adds support for Socionext AVE ethernet controller implemented
on UniPhier SoCs. This driver supports RGMII/RMII modes.
v4: https://www.spinics.net/lists/netdev/msg469294.html
The PHY patch included in v1 has already separated in:
http://www.spinics.net/lists/netdev/msg454595.html
Changes since v4:
- fix larger integer warning on AVE_PFMBYTE_MASK0
Changes since v3:
- remove checking dma address and use dma_set_mask() to restirct address
- replace ave_mdio_busywait() with read_poll_timeout()
- replace functions to access to registers with readl/writel() directly
- replace a function to access to macaddr with ave_hw_write_macaddr()
- change return value of ave_dma_map() to error value
- move mdiobus_unregister() from ave_remove() to ave_uninit()
- eliminate else block at the end of ave_dma_map()
- add mask definitions for packet filter
- sort bitmap definitions in descending order
- add error check to some functions
- rename and sort functions to clear sub-categories
- fix error value consistency
- remove unneeded initializers
- change type of constant arrays
Changes since v2:
- replace clk_get() with devm_clk_get()
- replace reset_control_get() with devm_reset_control_get_optional_shared()
- add error return when the error occurs on the above *_get functions
- sort soc data and compatible strings
- remove clearly obvious comments
- modify dt-bindings document consistent with these modifications
Changes since v1:
- add/remove devicetree properties and sub-node
- remove "internal-phy-interrupt" and "desc-bits" property
- add SoC data structures based on compatible strings
- add node operation to apply "mdio" sub-node
- add support for features
- add support for {get,set}_pauseparam and pause frame operations
- add support for ndo_get_stats64 instead of ndo_get_stats
- replace with desiable functions
- replace check for valid phy_mode with phy_interface{_mode}_is_rgmii()
- replace phy attach message with phy_attached_info()
- replace 32bit operation with {upper,lower}_32_bits() on ave_wdesc_addr()
- replace nway_reset and get_link with generic functions
- move operations to proper functions
- move phy_start_aneg() to ndo_open,
and remove unnecessary PHY interrupt operations
See http://www.spinics.net/lists/netdev/msg454590.html
- move irq initialization and descriptor memory allocation to ndo_open
- move initialization of reset and clock and mdiobus to ndo_init
- fix skbuffer operations
- fix skb alignment operations and add Rx buffer adjustment for descriptor
See http://www.spinics.net/lists/netdev/msg456014.html
- add error returns when dma_map_single() failed
- clean up code structures
- clean up wait-loop and wake-queue conditions
- add ave_wdesc_addr() and offset definitions
- add ave_macaddr_init() to clean up mac-address operation
- fix checking whether Tx entry is not enough
- fix supported features of phydev
- add necessary free/disable operations
- add phydev check on ave_{get,set}_wol()
- remove netif_carrier functions, phydev initializer, and Tx budget check
- change obsolate codes
- replace ndev->{base_addr,irq} with the members of ave_private
- rename goto labels and mask definitions, and remove unused codes
Kunihiko Hayashi (2):
dt-bindings: net: add DT bindings for Socionext UniPhier AVE
net: ethernet: socionext: add AVE ethernet driver
.../bindings/net/socionext,uniphier-ave4.txt | 48 +
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/socionext/Kconfig | 22 +
drivers/net/ethernet/socionext/Makefile | 5 +
drivers/net/ethernet/socionext/sni_ave.c | 1744 ++++++++++++++++++++
6 files changed, 1821 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
create mode 100644 drivers/net/ethernet/socionext/Kconfig
create mode 100644 drivers/net/ethernet/socionext/Makefile
create mode 100644 drivers/net/ethernet/socionext/sni_ave.c
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH net-next v5 1/2] dt-bindings: net: add DT bindings for Socionext UniPhier AVE
From: Kunihiko Hayashi @ 2017-12-11 7:57 UTC (permalink / raw)
To: David S. Miller, netdev
Cc: Andrew Lunn, Florian Fainelli, Rob Herring, Mark Rutland,
linux-arm-kernel, linux-kernel, devicetree, Masahiro Yamada,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
In-Reply-To: <1512979049-15930-1-git-send-email-hayashi.kunihiko@socionext.com>
DT bindings for the AVE ethernet controller found on Socionext's
UniPhier platforms.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
---
.../bindings/net/socionext,uniphier-ave4.txt | 48 ++++++++++++++++++++++
1 file changed, 48 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
diff --git a/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt b/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
new file mode 100644
index 0000000..4700377
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/socionext,uniphier-ave4.txt
@@ -0,0 +1,48 @@
+* Socionext AVE ethernet controller
+
+This describes the devicetree bindings for AVE ethernet controller
+implemented on Socionext UniPhier SoCs.
+
+Required properties:
+ - compatible: Should be
+ - "socionext,uniphier-pro4-ave4" : for Pro4 SoC
+ - "socionext,uniphier-pxs2-ave4" : for PXs2 SoC
+ - "socionext,uniphier-ld11-ave4" : for LD11 SoC
+ - "socionext,uniphier-ld20-ave4" : for LD20 SoC
+ - reg: Address where registers are mapped and size of region.
+ - interrupts: Should contain the MAC interrupt.
+ - phy-mode: See ethernet.txt in the same directory. Allow to choose
+ "rgmii", "rmii", or "mii" according to the PHY.
+ - phy-handle: Should point to the external phy device.
+ See ethernet.txt file in the same directory.
+ - clocks: A phandle to the clock for the MAC.
+
+Optional properties:
+ - resets: A phandle to the reset control for the MAC
+ - local-mac-address: See ethernet.txt in the same directory.
+
+Required subnode:
+ - mdio: Device tree subnode with the following required properties:
+ - #address-cells: Must be <1>.
+ - #size-cells: Must be <0>.
+ - reg: phy ID number, usually a small integer.
+
+Example:
+
+ ether: ethernet@65000000 {
+ compatible = "socionext,uniphier-ld20-ave4";
+ reg = <0x65000000 0x8500>;
+ interrupts = <0 66 4>;
+ phy-mode = "rgmii";
+ phy-handle = <ðphy>;
+ clocks = <&sys_clk 6>;
+ resets = <&sys_rst 6>;
+ local-mac-address = [00 00 00 00 00 00];
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ethphy: ethphy@1 {
+ reg = <1>;
+ };
+ };
+ };
--
2.7.4
^ permalink raw reply related
* [PATCH net-next v5 2/2] net: ethernet: socionext: add AVE ethernet driver
From: Kunihiko Hayashi @ 2017-12-11 7:57 UTC (permalink / raw)
To: David S. Miller, netdev
Cc: Andrew Lunn, Florian Fainelli, Rob Herring, Mark Rutland,
linux-arm-kernel, linux-kernel, devicetree, Masahiro Yamada,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
In-Reply-To: <1512979049-15930-1-git-send-email-hayashi.kunihiko@socionext.com>
The UniPhier platform from Socionext provides the AVE ethernet
controller that includes MAC and MDIO bus supporting RGMII/RMII
modes. The controller is named AVE.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/socionext/Kconfig | 22 +
drivers/net/ethernet/socionext/Makefile | 5 +
drivers/net/ethernet/socionext/sni_ave.c | 1744 ++++++++++++++++++++++++++++++
5 files changed, 1773 insertions(+)
create mode 100644 drivers/net/ethernet/socionext/Kconfig
create mode 100644 drivers/net/ethernet/socionext/Makefile
create mode 100644 drivers/net/ethernet/socionext/sni_ave.c
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index c604213..d50519e 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -170,6 +170,7 @@ source "drivers/net/ethernet/sis/Kconfig"
source "drivers/net/ethernet/sfc/Kconfig"
source "drivers/net/ethernet/sgi/Kconfig"
source "drivers/net/ethernet/smsc/Kconfig"
+source "drivers/net/ethernet/socionext/Kconfig"
source "drivers/net/ethernet/stmicro/Kconfig"
source "drivers/net/ethernet/sun/Kconfig"
source "drivers/net/ethernet/tehuti/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 39f62733..6cf5ade 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_SFC) += sfc/
obj-$(CONFIG_SFC_FALCON) += sfc/falcon/
obj-$(CONFIG_NET_VENDOR_SGI) += sgi/
obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
+obj-$(CONFIG_NET_VENDOR_SOCIONEXT) += socionext/
obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
obj-$(CONFIG_NET_VENDOR_SUN) += sun/
obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
diff --git a/drivers/net/ethernet/socionext/Kconfig b/drivers/net/ethernet/socionext/Kconfig
new file mode 100644
index 0000000..3a1829e
--- /dev/null
+++ b/drivers/net/ethernet/socionext/Kconfig
@@ -0,0 +1,22 @@
+config NET_VENDOR_SOCIONEXT
+ bool "Socionext ethernet drivers"
+ default y
+ ---help---
+ Option to select ethernet drivers for Socionext platforms.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Socionext devices. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_SOCIONEXT
+
+config SNI_AVE
+ tristate "Socionext AVE ethernet support"
+ depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
+ select PHYLIB
+ ---help---
+ Driver for gigabit ethernet MACs, called AVE, in the
+ Socionext UniPhier family.
+
+endif #NET_VENDOR_SOCIONEXT
diff --git a/drivers/net/ethernet/socionext/Makefile b/drivers/net/ethernet/socionext/Makefile
new file mode 100644
index 0000000..ab83df6
--- /dev/null
+++ b/drivers/net/ethernet/socionext/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for all ethernet ip drivers on Socionext platforms
+#
+obj-$(CONFIG_SNI_AVE) += sni_ave.o
diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c
new file mode 100644
index 0000000..7b293c2
--- /dev/null
+++ b/drivers/net/ethernet/socionext/sni_ave.c
@@ -0,0 +1,1744 @@
+/**
+ * sni_ave.c - Socionext UniPhier AVE ethernet driver
+ *
+ * Copyright 2014 Panasonic Corporation
+ * Copyright 2015-2017 Socionext Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+#include <linux/u64_stats_sync.h>
+
+/* General Register Group */
+#define AVE_IDR 0x000 /* ID */
+#define AVE_VR 0x004 /* Version */
+#define AVE_GRR 0x008 /* Global Reset */
+#define AVE_CFGR 0x00c /* Configuration */
+
+/* Interrupt Register Group */
+#define AVE_GIMR 0x100 /* Global Interrupt Mask */
+#define AVE_GISR 0x104 /* Global Interrupt Status */
+
+/* MAC Register Group */
+#define AVE_TXCR 0x200 /* TX Setup */
+#define AVE_RXCR 0x204 /* RX Setup */
+#define AVE_RXMAC1R 0x208 /* MAC address (lower) */
+#define AVE_RXMAC2R 0x20c /* MAC address (upper) */
+#define AVE_MDIOCTR 0x214 /* MDIO Control */
+#define AVE_MDIOAR 0x218 /* MDIO Address */
+#define AVE_MDIOWDR 0x21c /* MDIO Data */
+#define AVE_MDIOSR 0x220 /* MDIO Status */
+#define AVE_MDIORDR 0x224 /* MDIO Rd Data */
+
+/* Descriptor Control Register Group */
+#define AVE_DESCC 0x300 /* Descriptor Control */
+#define AVE_TXDC 0x304 /* TX Descriptor Configuration */
+#define AVE_RXDC0 0x308 /* RX Descriptor Ring0 Configuration */
+#define AVE_IIRQC 0x34c /* Interval IRQ Control */
+
+/* Packet Filter Register Group */
+#define AVE_PKTF_BASE 0x800 /* PF Base Address */
+#define AVE_PFMBYTE_BASE 0xd00 /* PF Mask Byte Base Address */
+#define AVE_PFMBIT_BASE 0xe00 /* PF Mask Bit Base Address */
+#define AVE_PFSEL_BASE 0xf00 /* PF Selector Base Address */
+#define AVE_PFEN 0xffc /* Packet Filter Enable */
+#define AVE_PKTF(ent) (AVE_PKTF_BASE + (ent) * 0x40)
+#define AVE_PFMBYTE(ent) (AVE_PFMBYTE_BASE + (ent) * 8)
+#define AVE_PFMBIT(ent) (AVE_PFMBIT_BASE + (ent) * 4)
+#define AVE_PFSEL(ent) (AVE_PFSEL_BASE + (ent) * 4)
+
+/* 64bit descriptor memory */
+#define AVE_DESC_SIZE_64 12 /* Descriptor Size */
+
+#define AVE_TXDM_64 0x1000 /* Tx Descriptor Memory */
+#define AVE_RXDM_64 0x1c00 /* Rx Descriptor Memory */
+
+#define AVE_TXDM_SIZE_64 0x0ba0 /* Tx Descriptor Memory Size 3KB */
+#define AVE_RXDM_SIZE_64 0x6000 /* Rx Descriptor Memory Size 24KB */
+
+/* 32bit descriptor memory */
+#define AVE_DESC_SIZE_32 8 /* Descriptor Size */
+
+#define AVE_TXDM_32 0x1000 /* Tx Descriptor Memory */
+#define AVE_RXDM_32 0x1800 /* Rx Descriptor Memory */
+
+#define AVE_TXDM_SIZE_32 0x07c0 /* Tx Descriptor Memory Size 2KB */
+#define AVE_RXDM_SIZE_32 0x4000 /* Rx Descriptor Memory Size 16KB */
+
+/* RMII Bridge Register Group */
+#define AVE_RSTCTRL 0x8028 /* Reset control */
+#define AVE_RSTCTRL_RMIIRST BIT(16)
+#define AVE_LINKSEL 0x8034 /* Link speed setting */
+#define AVE_LINKSEL_100M BIT(0)
+
+/* AVE_GRR */
+#define AVE_GRR_RXFFR BIT(5) /* Reset RxFIFO */
+#define AVE_GRR_PHYRST BIT(4) /* Reset external PHY */
+#define AVE_GRR_GRST BIT(0) /* Reset all MAC */
+
+/* AVE_CFGR */
+#define AVE_CFGR_FLE BIT(31) /* Filter Function */
+#define AVE_CFGR_CHE BIT(30) /* Checksum Function */
+#define AVE_CFGR_MII BIT(27) /* Func mode (1:MII/RMII, 0:RGMII) */
+#define AVE_CFGR_IPFCEN BIT(24) /* IP fragment sum Enable */
+
+/* AVE_GISR (common with GIMR) */
+#define AVE_GI_PHY BIT(24) /* PHY interrupt */
+#define AVE_GI_TX BIT(16) /* Tx complete */
+#define AVE_GI_RXERR BIT(8) /* Receive frame more than max size */
+#define AVE_GI_RXOVF BIT(7) /* Overflow at the RxFIFO */
+#define AVE_GI_RXDROP BIT(6) /* Drop packet */
+#define AVE_GI_RXIINT BIT(5) /* Interval interrupt */
+
+/* AVE_TXCR */
+#define AVE_TXCR_FLOCTR BIT(18) /* Flow control */
+#define AVE_TXCR_TXSPD_1G BIT(17)
+#define AVE_TXCR_TXSPD_100 BIT(16)
+
+/* AVE_RXCR */
+#define AVE_RXCR_RXEN BIT(30) /* Rx enable */
+#define AVE_RXCR_FDUPEN BIT(22) /* Interface mode */
+#define AVE_RXCR_FLOCTR BIT(21) /* Flow control */
+#define AVE_RXCR_AFEN BIT(19) /* MAC address filter */
+#define AVE_RXCR_DRPEN BIT(18) /* Drop pause frame */
+#define AVE_RXCR_MPSIZ_MASK GENMASK(10, 0)
+
+/* AVE_MDIOCTR */
+#define AVE_MDIOCTR_RREQ BIT(3) /* Read request */
+#define AVE_MDIOCTR_WREQ BIT(2) /* Write request */
+
+/* AVE_MDIOSR */
+#define AVE_MDIOSR_STS BIT(0) /* access status */
+
+/* AVE_DESCC */
+#define AVE_DESCC_STATUS_MASK GENMASK(31, 16)
+#define AVE_DESCC_RD0 BIT(8) /* Enable Rx descriptor Ring0 */
+#define AVE_DESCC_RDSTP BIT(4) /* Pause Rx descriptor */
+#define AVE_DESCC_TD BIT(0) /* Enable Tx descriptor */
+
+/* AVE_TXDC */
+#define AVE_TXDC_SIZE GENMASK(27, 16) /* Size of Tx descriptor */
+#define AVE_TXDC_ADDR GENMASK(11, 0) /* Start address */
+#define AVE_TXDC_ADDR_START 0
+
+/* AVE_RXDC0 */
+#define AVE_RXDC0_SIZE GENMASK(30, 16) /* Size of Rx descriptor */
+#define AVE_RXDC0_ADDR GENMASK(14, 0) /* Start address */
+#define AVE_RXDC0_ADDR_START 0
+
+/* AVE_IIRQC */
+#define AVE_IIRQC_EN0 BIT(27) /* Enable interval interrupt Ring0 */
+#define AVE_IIRQC_BSCK GENMASK(15, 0) /* Interval count unit */
+
+/* Command status for descriptor */
+#define AVE_STS_OWN BIT(31) /* Descriptor ownership */
+#define AVE_STS_INTR BIT(29) /* Request for interrupt */
+#define AVE_STS_OK BIT(27) /* Normal transmit */
+/* TX */
+#define AVE_STS_NOCSUM BIT(28) /* No use HW checksum */
+#define AVE_STS_1ST BIT(26) /* Head of buffer chain */
+#define AVE_STS_LAST BIT(25) /* Tail of buffer chain */
+#define AVE_STS_OWC BIT(21) /* Out of window,Late Collision */
+#define AVE_STS_EC BIT(20) /* Excess collision occurred */
+#define AVE_STS_PKTLEN_TX_MASK GENMASK(15, 0)
+/* RX */
+#define AVE_STS_CSSV BIT(21) /* Checksum check performed */
+#define AVE_STS_CSER BIT(20) /* Checksum error detected */
+#define AVE_STS_PKTLEN_RX_MASK GENMASK(10, 0)
+
+/* Packet filter */
+#define AVE_PFMBYTE_MASK0 (GENMASK(31, 8) | GENMASK(5, 0))
+#define AVE_PFMBYTE_MASK1 GENMASK(25, 0)
+#define AVE_PFMBIT_MASK GENMASK(15, 0)
+
+#define AVE_PF_SIZE 17 /* Number of all packet filter */
+#define AVE_PF_MULTICAST_SIZE 7 /* Number of multicast filter */
+
+#define AVE_PFNUM_FILTER 0 /* No.0 */
+#define AVE_PFNUM_UNICAST 1 /* No.1 */
+#define AVE_PFNUM_BROADCAST 2 /* No.2 */
+#define AVE_PFNUM_MULTICAST 11 /* No.11-17 */
+
+/* NETIF Message control */
+#define AVE_DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | \
+ NETIF_MSG_IFDOWN | \
+ NETIF_MSG_IFUP | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR)
+
+/* Parameter for descriptor */
+#define AVE_NR_TXDESC 32 /* Tx descriptor */
+#define AVE_NR_RXDESC 64 /* Rx descriptor */
+
+#define AVE_DESC_OFS_CMDSTS 0
+#define AVE_DESC_OFS_ADDRL 4
+#define AVE_DESC_OFS_ADDRU 8
+
+/* Parameter for ethernet frame */
+#define AVE_MAX_ETHFRAME 1518
+
+/* Parameter for interrupt */
+#define AVE_INTM_COUNT 20
+#define AVE_FORCE_TXINTCNT 1
+
+#define IS_DESC_64BIT(p) ((p)->data->is_desc_64bit)
+
+enum desc_id {
+ AVE_DESCID_RX,
+ AVE_DESCID_TX,
+};
+
+enum desc_state {
+ AVE_DESC_RX_PERMIT,
+ AVE_DESC_RX_SUSPEND,
+ AVE_DESC_START,
+ AVE_DESC_STOP,
+};
+
+struct ave_desc {
+ struct sk_buff *skbs;
+ dma_addr_t skbs_dma;
+ size_t skbs_dmalen;
+};
+
+struct ave_desc_info {
+ u32 ndesc; /* number of descriptor */
+ u32 daddr; /* start address of descriptor */
+ u32 proc_idx; /* index of processing packet */
+ u32 done_idx; /* index of processed packet */
+ struct ave_desc *desc; /* skb info related descriptor */
+};
+
+struct ave_soc_data {
+ bool is_desc_64bit;
+};
+
+struct ave_stats {
+ struct u64_stats_sync syncp;
+ u64 packets;
+ u64 bytes;
+ u64 errors;
+ u64 dropped;
+ u64 collisions;
+ u64 fifo_errors;
+};
+
+struct ave_private {
+ void __iomem *base;
+ int irq;
+ int phy_id;
+ unsigned int desc_size;
+ u32 msg_enable;
+ struct clk *clk;
+ struct reset_control *rst;
+ phy_interface_t phy_mode;
+ struct phy_device *phydev;
+ struct mii_bus *mdio;
+
+ /* stats */
+ struct ave_stats stats_rx;
+ struct ave_stats stats_tx;
+
+ /* NAPI support */
+ struct net_device *ndev;
+ struct napi_struct napi_rx;
+ struct napi_struct napi_tx;
+
+ /* descriptor */
+ struct ave_desc_info rx;
+ struct ave_desc_info tx;
+
+ /* flow control */
+ int pause_auto;
+ int pause_rx;
+ int pause_tx;
+
+ const struct ave_soc_data *data;
+};
+
+static inline u32 ave_desc_read(struct net_device *ndev, enum desc_id id,
+ int entry, int offset)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 addr = (id == AVE_DESCID_TX) ? priv->tx.daddr : priv->rx.daddr;
+
+ addr += entry * priv->desc_size + offset;
+
+ return readl(priv->base + addr);
+}
+
+static inline u32 ave_desc_read_cmdsts(struct net_device *ndev, enum desc_id id,
+ int entry)
+{
+ return ave_desc_read(ndev, id, entry, AVE_DESC_OFS_CMDSTS);
+}
+
+static inline void ave_desc_write(struct net_device *ndev, enum desc_id id,
+ int entry, int offset, u32 val)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 addr = (id == AVE_DESCID_TX) ? priv->tx.daddr : priv->rx.daddr;
+
+ addr += entry * priv->desc_size + offset;
+
+ writel(val, priv->base + addr);
+}
+
+static inline void ave_desc_write_cmdsts(struct net_device *ndev,
+ enum desc_id id, int entry, u32 val)
+{
+ ave_desc_write(ndev, id, entry, AVE_DESC_OFS_CMDSTS, val);
+}
+
+static inline void ave_desc_write_addr(struct net_device *ndev,
+ enum desc_id id, int entry,
+ dma_addr_t paddr)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ ave_desc_write(ndev, id, entry, AVE_DESC_OFS_ADDRL,
+ lower_32_bits(paddr));
+ if (IS_DESC_64BIT(priv))
+ ave_desc_write(ndev, id,
+ entry, AVE_DESC_OFS_ADDRU,
+ upper_32_bits(paddr));
+}
+
+static inline u32 ave_irq_disable_all(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 ret;
+
+ ret = readl(priv->base + AVE_GIMR);
+ writel(0, priv->base + AVE_GIMR);
+
+ return ret;
+}
+
+static inline void ave_irq_restore(struct net_device *ndev, u32 val)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ writel(val, priv->base + AVE_GIMR);
+}
+
+static inline void ave_irq_enable(struct net_device *ndev, u32 bitflag)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ writel(readl(priv->base + AVE_GIMR) | bitflag, priv->base + AVE_GIMR);
+ writel(bitflag, priv->base + AVE_GISR);
+}
+
+static inline void ave_irq_disable(struct net_device *ndev, u32 bitflag)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ writel(readl(priv->base + AVE_GIMR) & ~bitflag, priv->base + AVE_GIMR);
+}
+
+static void ave_hw_write_macaddr(struct net_device *ndev,
+ const unsigned char *mac_addr,
+ int reg1, int reg2)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ writel(mac_addr[0] | mac_addr[1] << 8 |
+ mac_addr[2] << 16 | mac_addr[3] << 24, priv->base + reg1);
+ writel(mac_addr[4] | mac_addr[5] << 8, priv->base + reg2);
+}
+
+static void ave_hw_read_version(struct net_device *ndev, char *buf, int len)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 major, minor, vr;
+
+ vr = readl(priv->base + AVE_VR);
+ major = (vr & GENMASK(15, 8)) >> 8;
+ minor = (vr & GENMASK(7, 0));
+ snprintf(buf, len, "v%u.%u", major, minor);
+}
+
+static void ave_ethtool_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct device *dev = ndev->dev.parent;
+
+ strlcpy(info->driver, dev->driver->name, sizeof(info->driver));
+ strlcpy(info->bus_info, dev_name(dev), sizeof(info->bus_info));
+ ave_hw_read_version(ndev, info->fw_version, sizeof(info->fw_version));
+}
+
+static u32 ave_ethtool_get_msglevel(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ return priv->msg_enable;
+}
+
+static void ave_ethtool_set_msglevel(struct net_device *ndev, u32 val)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ priv->msg_enable = val;
+}
+
+static void ave_ethtool_get_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ if (ndev->phydev)
+ phy_ethtool_get_wol(ndev->phydev, wol);
+}
+
+static int ave_ethtool_set_wol(struct net_device *ndev,
+ struct ethtool_wolinfo *wol)
+{
+ int ret;
+
+ if (!ndev->phydev ||
+ (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)))
+ return -EOPNOTSUPP;
+
+ ret = phy_ethtool_set_wol(ndev->phydev, wol);
+ if (!ret)
+ device_set_wakeup_enable(&ndev->dev, !!wol->wolopts);
+
+ return ret;
+}
+
+static void ave_ethtool_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ pause->autoneg = priv->pause_auto;
+ pause->rx_pause = priv->pause_rx;
+ pause->tx_pause = priv->pause_tx;
+}
+
+static int ave_ethtool_set_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct phy_device *phydev = ndev->phydev;
+
+ if (!phydev)
+ return -EINVAL;
+
+ priv->pause_auto = pause->autoneg;
+ priv->pause_rx = pause->rx_pause;
+ priv->pause_tx = pause->tx_pause;
+
+ phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+ if (pause->rx_pause)
+ phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+ if (pause->tx_pause)
+ phydev->advertising ^= ADVERTISED_Asym_Pause;
+
+ if (pause->autoneg) {
+ if (netif_running(ndev))
+ phy_start_aneg(phydev);
+ }
+
+ return 0;
+}
+
+static const struct ethtool_ops ave_ethtool_ops = {
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .get_drvinfo = ave_ethtool_get_drvinfo,
+ .nway_reset = phy_ethtool_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = ave_ethtool_get_msglevel,
+ .set_msglevel = ave_ethtool_set_msglevel,
+ .get_wol = ave_ethtool_get_wol,
+ .set_wol = ave_ethtool_set_wol,
+ .get_pauseparam = ave_ethtool_get_pauseparam,
+ .set_pauseparam = ave_ethtool_set_pauseparam,
+};
+
+static int ave_mdiobus_read(struct mii_bus *bus, int phyid, int regnum)
+{
+ struct net_device *ndev = bus->priv;
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 mdioctl, mdiosr;
+ int ret;
+
+ /* write address */
+ writel((phyid << 8) | regnum, priv->base + AVE_MDIOAR);
+
+ /* read request */
+ mdioctl = readl(priv->base + AVE_MDIOCTR);
+ writel((mdioctl | AVE_MDIOCTR_RREQ) & ~AVE_MDIOCTR_WREQ,
+ priv->base + AVE_MDIOCTR);
+
+ ret = readl_poll_timeout(priv->base + AVE_MDIOSR, mdiosr,
+ !(mdiosr & AVE_MDIOSR_STS), 20, 2000);
+ if (ret) {
+ netdev_err(ndev, "failed to read (phy:%d reg:%x)\n",
+ phyid, regnum);
+ return ret;
+ }
+
+ return readl(priv->base + AVE_MDIORDR) & GENMASK(15, 0);
+}
+
+static int ave_mdiobus_write(struct mii_bus *bus,
+ int phyid, int regnum, u16 val)
+{
+ struct net_device *ndev = bus->priv;
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 mdioctl, mdiosr;
+ int ret;
+
+ /* write address */
+ writel((phyid << 8) | regnum, priv->base + AVE_MDIOAR);
+
+ /* write data */
+ writel(val, priv->base + AVE_MDIOWDR);
+
+ /* write request */
+ mdioctl = readl(priv->base + AVE_MDIOCTR);
+ writel((mdioctl | AVE_MDIOCTR_WREQ) & ~AVE_MDIOCTR_RREQ,
+ priv->base + AVE_MDIOCTR);
+
+ ret = readl_poll_timeout(priv->base + AVE_MDIOSR, mdiosr,
+ !(mdiosr & AVE_MDIOSR_STS), 20, 2000);
+ if (ret)
+ netdev_err(ndev, "failed to write (phy:%d reg:%x)\n",
+ phyid, regnum);
+
+ return ret;
+}
+
+static int ave_dma_map(struct net_device *ndev, struct ave_desc *desc,
+ void *ptr, size_t len,
+ enum dma_data_direction dir, dma_addr_t *paddr)
+{
+ dma_addr_t map_addr;
+
+ map_addr = dma_map_single(ndev->dev.parent, ptr, len, dir);
+ if (unlikely(dma_mapping_error(ndev->dev.parent, map_addr)))
+ return -ENOMEM;
+
+ desc->skbs_dma = map_addr;
+ desc->skbs_dmalen = len;
+ *paddr = map_addr;
+
+ return 0;
+}
+
+static void ave_dma_unmap(struct net_device *ndev, struct ave_desc *desc,
+ enum dma_data_direction dir)
+{
+ if (!desc->skbs_dma)
+ return;
+
+ dma_unmap_single(ndev->dev.parent,
+ desc->skbs_dma, desc->skbs_dmalen, dir);
+ desc->skbs_dma = 0;
+}
+
+/* Prepare Rx descriptor and memory */
+static int ave_rxdesc_prepare(struct net_device *ndev, int entry)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct sk_buff *skb;
+ dma_addr_t paddr;
+ int ret;
+
+ skb = priv->rx.desc[entry].skbs;
+ if (!skb) {
+ skb = netdev_alloc_skb_ip_align(ndev,
+ AVE_MAX_ETHFRAME);
+ if (!skb) {
+ netdev_err(ndev, "can't allocate skb for Rx\n");
+ return -ENOMEM;
+ }
+ }
+
+ /* set disable to cmdsts */
+ ave_desc_write_cmdsts(ndev, AVE_DESCID_RX, entry,
+ AVE_STS_INTR | AVE_STS_OWN);
+
+ /* map Rx buffer
+ * Rx buffer set to the Rx descriptor has two restrictions:
+ * - Rx buffer address is 4 byte aligned.
+ * - Rx buffer begins with 2 byte headroom, and data will be put from
+ * (buffer + 2).
+ * To satisfy this, specify the address to put back the buffer
+ * pointer advanced by NET_IP_ALIGN by netdev_alloc_skb_ip_align(),
+ * and expand the map size by NET_IP_ALIGN.
+ */
+ ret = ave_dma_map(ndev, &priv->rx.desc[entry],
+ skb->data - NET_IP_ALIGN,
+ AVE_MAX_ETHFRAME + NET_IP_ALIGN,
+ DMA_FROM_DEVICE, &paddr);
+ if (ret) {
+ netdev_err(ndev, "can't map skb for Rx\n");
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ priv->rx.desc[entry].skbs = skb;
+
+ /* set buffer pointer */
+ ave_desc_write_addr(ndev, AVE_DESCID_RX, entry, paddr);
+
+ /* set enable to cmdsts */
+ ave_desc_write_cmdsts(ndev, AVE_DESCID_RX, entry,
+ AVE_STS_INTR | AVE_MAX_ETHFRAME);
+
+ return ret;
+}
+
+/* Switch state of descriptor */
+static int ave_desc_switch(struct net_device *ndev, enum desc_state state)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ int ret = 0;
+ u32 val;
+
+ switch (state) {
+ case AVE_DESC_START:
+ writel(AVE_DESCC_TD | AVE_DESCC_RD0, priv->base + AVE_DESCC);
+ break;
+
+ case AVE_DESC_STOP:
+ writel(0, priv->base + AVE_DESCC);
+ if (readl_poll_timeout(priv->base + AVE_DESCC, val, !val,
+ 150, 15000)) {
+ netdev_err(ndev, "can't stop descriptor\n");
+ ret = -EBUSY;
+ }
+ break;
+
+ case AVE_DESC_RX_SUSPEND:
+ val = readl(priv->base + AVE_DESCC);
+ val |= AVE_DESCC_RDSTP;
+ val &= ~AVE_DESCC_STATUS_MASK;
+ writel(val, priv->base + AVE_DESCC);
+ if (readl_poll_timeout(priv->base + AVE_DESCC, val,
+ val & (AVE_DESCC_RDSTP << 16),
+ 150, 150000)) {
+ netdev_err(ndev, "can't suspend descriptor\n");
+ ret = -EBUSY;
+ }
+ break;
+
+ case AVE_DESC_RX_PERMIT:
+ val = readl(priv->base + AVE_DESCC);
+ val &= ~AVE_DESCC_RDSTP;
+ val &= ~AVE_DESCC_STATUS_MASK;
+ writel(val, priv->base + AVE_DESCC);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ave_tx_complete(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 proc_idx, done_idx, ndesc, cmdsts;
+ unsigned int nr_freebuf = 0;
+ unsigned int tx_packets = 0;
+ unsigned int tx_bytes = 0;
+
+ proc_idx = priv->tx.proc_idx;
+ done_idx = priv->tx.done_idx;
+ ndesc = priv->tx.ndesc;
+
+ /* free pre-stored skb from done_idx to proc_idx */
+ while (proc_idx != done_idx) {
+ cmdsts = ave_desc_read_cmdsts(ndev, AVE_DESCID_TX, done_idx);
+
+ /* do nothing if owner is HW (==1 for Tx) */
+ if (cmdsts & AVE_STS_OWN)
+ break;
+
+ /* check Tx status and updates statistics */
+ if (cmdsts & AVE_STS_OK) {
+ tx_bytes += cmdsts & AVE_STS_PKTLEN_TX_MASK;
+ /* success */
+ if (cmdsts & AVE_STS_LAST)
+ tx_packets++;
+ } else {
+ /* error */
+ if (cmdsts & AVE_STS_LAST) {
+ priv->stats_tx.errors++;
+ if (cmdsts & (AVE_STS_OWC | AVE_STS_EC))
+ priv->stats_tx.collisions++;
+ }
+ }
+
+ /* release skb */
+ if (priv->tx.desc[done_idx].skbs) {
+ ave_dma_unmap(ndev, &priv->tx.desc[done_idx],
+ DMA_TO_DEVICE);
+ dev_consume_skb_any(priv->tx.desc[done_idx].skbs);
+ priv->tx.desc[done_idx].skbs = NULL;
+ nr_freebuf++;
+ }
+ done_idx = (done_idx + 1) % ndesc;
+ }
+
+ priv->tx.done_idx = done_idx;
+
+ /* update stats */
+ u64_stats_update_begin(&priv->stats_tx.syncp);
+ priv->stats_tx.packets += tx_packets;
+ priv->stats_tx.bytes += tx_bytes;
+ u64_stats_update_end(&priv->stats_tx.syncp);
+
+ /* wake queue for freeing buffer */
+ if (unlikely(netif_queue_stopped(ndev)) && nr_freebuf)
+ netif_wake_queue(ndev);
+
+ return nr_freebuf;
+}
+
+static int ave_rx_receive(struct net_device *ndev, int num)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct sk_buff *skb;
+ u32 proc_idx, done_idx, ndesc, cmdsts;
+ int restpkt, npkts;
+ unsigned int pktlen;
+ unsigned int rx_packets = 0;
+ unsigned int rx_bytes = 0;
+
+ proc_idx = priv->rx.proc_idx;
+ done_idx = priv->rx.done_idx;
+ ndesc = priv->rx.ndesc;
+ restpkt = ((proc_idx + ndesc - 1) - done_idx) % ndesc;
+
+ for (npkts = 0; npkts < num; npkts++) {
+ /* we can't receive more packet, so fill desc quickly */
+ if (--restpkt < 0)
+ break;
+
+ cmdsts = ave_desc_read_cmdsts(ndev, AVE_DESCID_RX, proc_idx);
+
+ /* do nothing if owner is HW (==0 for Rx) */
+ if (!(cmdsts & AVE_STS_OWN))
+ break;
+
+ if (!(cmdsts & AVE_STS_OK)) {
+ priv->stats_rx.errors++;
+ proc_idx = (proc_idx + 1) % ndesc;
+ continue;
+ }
+
+ pktlen = cmdsts & AVE_STS_PKTLEN_RX_MASK;
+
+ /* get skbuff for rx */
+ skb = priv->rx.desc[proc_idx].skbs;
+ priv->rx.desc[proc_idx].skbs = NULL;
+
+ ave_dma_unmap(ndev, &priv->rx.desc[proc_idx], DMA_FROM_DEVICE);
+
+ skb->dev = ndev;
+ skb_put(skb, pktlen);
+ skb->protocol = eth_type_trans(skb, ndev);
+
+ if ((cmdsts & AVE_STS_CSSV) && (!(cmdsts & AVE_STS_CSER)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ rx_packets++;
+ rx_bytes += pktlen;
+
+ netif_receive_skb(skb);
+
+ proc_idx = (proc_idx + 1) % ndesc;
+ }
+
+ priv->rx.proc_idx = proc_idx;
+
+ /* update stats */
+ u64_stats_update_begin(&priv->stats_rx.syncp);
+ priv->stats_rx.packets += rx_packets;
+ priv->stats_rx.bytes += rx_bytes;
+ u64_stats_update_end(&priv->stats_rx.syncp);
+
+ /* refill the Rx buffers */
+ while (proc_idx != done_idx) {
+ if (ave_rxdesc_prepare(ndev, done_idx))
+ break;
+ done_idx = (done_idx + 1) % ndesc;
+ }
+
+ priv->rx.done_idx = done_idx;
+
+ return npkts;
+}
+
+static int ave_napi_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct ave_private *priv;
+ struct net_device *ndev;
+ int num;
+
+ priv = container_of(napi, struct ave_private, napi_rx);
+ ndev = priv->ndev;
+
+ num = ave_rx_receive(ndev, budget);
+ if (num < budget) {
+ napi_complete_done(napi, num);
+
+ /* enable Rx interrupt when NAPI finishes */
+ ave_irq_enable(ndev, AVE_GI_RXIINT);
+ }
+
+ return num;
+}
+
+static int ave_napi_poll_tx(struct napi_struct *napi, int budget)
+{
+ struct ave_private *priv;
+ struct net_device *ndev;
+ int num;
+
+ priv = container_of(napi, struct ave_private, napi_tx);
+ ndev = priv->ndev;
+
+ num = ave_tx_complete(ndev);
+ napi_complete(napi);
+
+ /* enable Tx interrupt when NAPI finishes */
+ ave_irq_enable(ndev, AVE_GI_TX);
+
+ return num;
+}
+
+static void ave_global_reset(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 val;
+
+ /* set config register */
+ val = AVE_CFGR_FLE | AVE_CFGR_IPFCEN | AVE_CFGR_CHE;
+ if (!phy_interface_mode_is_rgmii(priv->phy_mode))
+ val |= AVE_CFGR_MII;
+ writel(val, priv->base + AVE_CFGR);
+
+ /* reset RMII register */
+ val = readl(priv->base + AVE_RSTCTRL);
+ val &= ~AVE_RSTCTRL_RMIIRST;
+ writel(val, priv->base + AVE_RSTCTRL);
+
+ /* assert reset */
+ writel(AVE_GRR_GRST | AVE_GRR_PHYRST, priv->base + AVE_GRR);
+ msleep(20);
+
+ /* 1st, negate PHY reset only */
+ writel(AVE_GRR_GRST, priv->base + AVE_GRR);
+ msleep(40);
+
+ /* negate reset */
+ writel(0, priv->base + AVE_GRR);
+ msleep(40);
+
+ /* negate RMII register */
+ val = readl(priv->base + AVE_RSTCTRL);
+ val |= AVE_RSTCTRL_RMIIRST;
+ writel(val, priv->base + AVE_RSTCTRL);
+
+ ave_irq_disable_all(ndev);
+}
+
+static void ave_rxfifo_reset(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 rxcr_org;
+
+ /* save and disable MAC receive op */
+ rxcr_org = readl(priv->base + AVE_RXCR);
+ writel(rxcr_org & (~AVE_RXCR_RXEN), priv->base + AVE_RXCR);
+
+ /* suspend Rx descriptor */
+ ave_desc_switch(ndev, AVE_DESC_RX_SUSPEND);
+
+ /* receive all packets before descriptor starts */
+ ave_rx_receive(ndev, priv->rx.ndesc);
+
+ /* assert reset */
+ writel(AVE_GRR_RXFFR, priv->base + AVE_GRR);
+ usleep_range(40, 50);
+
+ /* negate reset */
+ writel(0, priv->base + AVE_GRR);
+ usleep_range(10, 20);
+
+ /* negate interrupt status */
+ writel(AVE_GI_RXOVF, priv->base + AVE_GISR);
+
+ /* permit descriptor */
+ ave_desc_switch(ndev, AVE_DESC_RX_PERMIT);
+
+ /* restore MAC reccieve op */
+ writel(rxcr_org, priv->base + AVE_RXCR);
+}
+
+static irqreturn_t ave_irq_handler(int irq, void *netdev)
+{
+ struct net_device *ndev = (struct net_device *)netdev;
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 gimr_val, gisr_val;
+
+ gimr_val = ave_irq_disable_all(ndev);
+
+ /* get interrupt status */
+ gisr_val = readl(priv->base + AVE_GISR);
+
+ /* PHY */
+ if (gisr_val & AVE_GI_PHY)
+ writel(AVE_GI_PHY, priv->base + AVE_GISR);
+
+ /* check exceeding packet */
+ if (gisr_val & AVE_GI_RXERR) {
+ writel(AVE_GI_RXERR, priv->base + AVE_GISR);
+ netdev_err(ndev, "receive a packet exceeding frame buffer\n");
+ }
+
+ gisr_val &= gimr_val;
+ if (!gisr_val)
+ goto exit_isr;
+
+ /* RxFIFO overflow */
+ if (gisr_val & AVE_GI_RXOVF) {
+ priv->stats_rx.fifo_errors++;
+ ave_rxfifo_reset(ndev);
+ goto exit_isr;
+ }
+
+ /* Rx drop */
+ if (gisr_val & AVE_GI_RXDROP) {
+ priv->stats_rx.dropped++;
+ writel(AVE_GI_RXDROP, priv->base + AVE_GISR);
+ }
+
+ /* Rx interval */
+ if (gisr_val & AVE_GI_RXIINT) {
+ napi_schedule(&priv->napi_rx);
+ /* still force to disable Rx interrupt until NAPI finishes */
+ gimr_val &= ~AVE_GI_RXIINT;
+ }
+
+ /* Tx completed */
+ if (gisr_val & AVE_GI_TX) {
+ napi_schedule(&priv->napi_tx);
+ /* still force to disable Tx interrupt until NAPI finishes */
+ gimr_val &= ~AVE_GI_TX;
+ }
+
+exit_isr:
+ ave_irq_restore(ndev, gimr_val);
+
+ return IRQ_HANDLED;
+}
+
+static int ave_pfsel_start(struct net_device *ndev, unsigned int entry)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 val;
+
+ if (WARN_ON(entry > AVE_PF_SIZE))
+ return -EINVAL;
+
+ val = readl(priv->base + AVE_PFEN);
+ writel(val | BIT(entry), priv->base + AVE_PFEN);
+
+ return 0;
+}
+
+static int ave_pfsel_stop(struct net_device *ndev, unsigned int entry)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 val;
+
+ if (WARN_ON(entry > AVE_PF_SIZE))
+ return -EINVAL;
+
+ val = readl(priv->base + AVE_PFEN);
+ writel(val & ~BIT(entry), priv->base + AVE_PFEN);
+
+ return 0;
+}
+
+static int ave_pfsel_set_macaddr(struct net_device *ndev,
+ unsigned int entry,
+ const unsigned char *mac_addr,
+ unsigned int set_size)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ if (WARN_ON(entry > AVE_PF_SIZE))
+ return -EINVAL;
+ if (WARN_ON(set_size > 6))
+ return -EINVAL;
+
+ ave_pfsel_stop(ndev, entry);
+
+ /* set MAC address for the filter */
+ ave_hw_write_macaddr(ndev, mac_addr,
+ AVE_PKTF(entry), AVE_PKTF(entry) + 4);
+
+ /* set byte mask */
+ writel(GENMASK(31, set_size) & AVE_PFMBYTE_MASK0,
+ priv->base + AVE_PFMBYTE(entry));
+ writel(AVE_PFMBYTE_MASK1, priv->base + AVE_PFMBYTE(entry) + 4);
+
+ /* set bit mask filter */
+ writel(AVE_PFMBIT_MASK, priv->base + AVE_PFMBIT(entry));
+
+ /* set selector to ring 0 */
+ writel(0, priv->base + AVE_PFSEL(entry));
+
+ /* restart filter */
+ ave_pfsel_start(ndev, entry);
+
+ return 0;
+}
+
+static void ave_pfsel_set_promisc(struct net_device *ndev,
+ unsigned int entry, u32 rxring)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ if (WARN_ON(entry > AVE_PF_SIZE))
+ return;
+
+ ave_pfsel_stop(ndev, entry);
+
+ /* set byte mask */
+ writel(AVE_PFMBYTE_MASK0, priv->base + AVE_PFMBYTE(entry));
+ writel(AVE_PFMBYTE_MASK1, priv->base + AVE_PFMBYTE(entry) + 4);
+
+ /* set bit mask filter */
+ writel(AVE_PFMBIT_MASK, priv->base + AVE_PFMBIT(entry));
+
+ /* set selector to rxring */
+ writel(rxring, priv->base + AVE_PFSEL(entry));
+
+ ave_pfsel_start(ndev, entry);
+}
+
+static void ave_pfsel_init(struct net_device *ndev)
+{
+ int i;
+ unsigned char bcast_mac[ETH_ALEN];
+
+ eth_broadcast_addr(bcast_mac);
+
+ for (i = 0; i < AVE_PF_SIZE; i++)
+ ave_pfsel_stop(ndev, i);
+
+ /* promiscious entry, select ring 0 */
+ ave_pfsel_set_promisc(ndev, AVE_PFNUM_FILTER, 0);
+
+ /* unicast entry */
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_UNICAST, ndev->dev_addr, 6);
+
+ /* broadcast entry */
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_BROADCAST, bcast_mac, 6);
+}
+
+static void ave_phy_adjust_link(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct phy_device *phydev = ndev->phydev;
+ u32 val, txcr, rxcr, rxcr_org;
+ u16 rmt_adv = 0, lcl_adv = 0;
+ u8 cap;
+
+ /* set RGMII speed */
+ val = readl(priv->base + AVE_TXCR);
+ val &= ~(AVE_TXCR_TXSPD_100 | AVE_TXCR_TXSPD_1G);
+
+ if (phy_interface_is_rgmii(phydev) && phydev->speed == SPEED_1000)
+ val |= AVE_TXCR_TXSPD_1G;
+ else if (phydev->speed == SPEED_100)
+ val |= AVE_TXCR_TXSPD_100;
+
+ writel(val, priv->base + AVE_TXCR);
+
+ /* set RMII speed (100M/10M only) */
+ if (!phy_interface_is_rgmii(phydev)) {
+ val = readl(priv->base + AVE_LINKSEL);
+ if (phydev->speed == SPEED_10)
+ val &= ~AVE_LINKSEL_100M;
+ else
+ val |= AVE_LINKSEL_100M;
+ writel(val, priv->base + AVE_LINKSEL);
+ }
+
+ /* check current RXCR/TXCR */
+ rxcr = readl(priv->base + AVE_RXCR);
+ txcr = readl(priv->base + AVE_TXCR);
+ rxcr_org = rxcr;
+
+ if (phydev->duplex) {
+ rxcr |= AVE_RXCR_FDUPEN;
+
+ if (phydev->pause)
+ rmt_adv |= LPA_PAUSE_CAP;
+ if (phydev->asym_pause)
+ rmt_adv |= LPA_PAUSE_ASYM;
+ if (phydev->advertising & ADVERTISED_Pause)
+ lcl_adv |= ADVERTISE_PAUSE_CAP;
+ if (phydev->advertising & ADVERTISED_Asym_Pause)
+ lcl_adv |= ADVERTISE_PAUSE_ASYM;
+
+ cap = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+ if (cap & FLOW_CTRL_TX)
+ txcr |= AVE_TXCR_FLOCTR;
+ else
+ txcr &= ~AVE_TXCR_FLOCTR;
+ if (cap & FLOW_CTRL_RX)
+ rxcr |= AVE_RXCR_FLOCTR;
+ else
+ rxcr &= ~AVE_RXCR_FLOCTR;
+ } else {
+ rxcr &= ~AVE_RXCR_FDUPEN;
+ rxcr &= ~AVE_RXCR_FLOCTR;
+ txcr &= ~AVE_TXCR_FLOCTR;
+ }
+
+ if (rxcr_org != rxcr) {
+ /* disable Rx mac */
+ writel(rxcr & ~AVE_RXCR_RXEN, priv->base + AVE_RXCR);
+ /* change and enable TX/Rx mac */
+ writel(txcr, priv->base + AVE_TXCR);
+ writel(rxcr, priv->base + AVE_RXCR);
+ }
+
+ phy_print_status(phydev);
+}
+
+static void ave_macaddr_init(struct net_device *ndev)
+{
+ ave_hw_write_macaddr(ndev, ndev->dev_addr, AVE_RXMAC1R, AVE_RXMAC2R);
+
+ /* pfsel unicast entry */
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_UNICAST, ndev->dev_addr, 6);
+}
+
+static int ave_init(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct device *dev = ndev->dev.parent;
+ struct device_node *np = dev->of_node, *mdio_np;
+ struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
+ struct phy_device *phydev;
+ int ret;
+
+ /* enable clk because of hw access until ndo_open */
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "can't enable clock\n");
+ return ret;
+ }
+ ret = reset_control_deassert(priv->rst);
+ if (ret) {
+ dev_err(dev, "can't deassert reset\n");
+ goto out_clk_disable;
+ }
+
+ ave_global_reset(ndev);
+
+ mdio_np = of_get_child_by_name(np, "mdio");
+ if (!mdio_np) {
+ dev_err(dev, "mdio node not found\n");
+ ret = -EINVAL;
+ goto out_reset_assert;
+ }
+ ret = of_mdiobus_register(priv->mdio, mdio_np);
+ of_node_put(mdio_np);
+ if (ret) {
+ dev_err(dev, "failed to register mdiobus\n");
+ goto out_reset_assert;
+ }
+
+ phydev = of_phy_get_and_connect(ndev, np, ave_phy_adjust_link);
+ if (!phydev) {
+ dev_err(dev, "could not attach to PHY\n");
+ ret = -ENODEV;
+ goto out_mdio_unregister;
+ }
+
+ priv->phydev = phydev;
+
+ phy_ethtool_get_wol(phydev, &wol);
+ device_set_wakeup_capable(&ndev->dev, !!wol.supported);
+
+ if (!phy_interface_is_rgmii(phydev)) {
+ phydev->supported &= ~PHY_GBIT_FEATURES;
+ phydev->supported |= PHY_BASIC_FEATURES;
+ }
+ phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
+ phy_attached_info(phydev);
+
+ return 0;
+
+out_mdio_unregister:
+ mdiobus_unregister(priv->mdio);
+out_reset_assert:
+ reset_control_assert(priv->rst);
+out_clk_disable:
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static void ave_uninit(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+
+ phy_disconnect(priv->phydev);
+ mdiobus_unregister(priv->mdio);
+
+ /* disable clk because of hw access after ndo_stop */
+ reset_control_assert(priv->rst);
+ clk_disable_unprepare(priv->clk);
+}
+
+static int ave_open(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ int entry;
+ int ret;
+ u32 val;
+
+ ret = request_irq(priv->irq, ave_irq_handler, IRQF_SHARED, ndev->name,
+ ndev);
+ if (ret)
+ return ret;
+
+ priv->tx.desc = kcalloc(priv->tx.ndesc, sizeof(*priv->tx.desc),
+ GFP_KERNEL);
+ if (!priv->tx.desc) {
+ ret = -ENOMEM;
+ goto out_free_irq;
+ }
+
+ priv->rx.desc = kcalloc(priv->rx.ndesc, sizeof(*priv->rx.desc),
+ GFP_KERNEL);
+ if (!priv->rx.desc) {
+ kfree(priv->tx.desc);
+ ret = -ENOMEM;
+ goto out_free_irq;
+ }
+
+ /* initialize Tx work and descriptor */
+ priv->tx.proc_idx = 0;
+ priv->tx.done_idx = 0;
+ for (entry = 0; entry < priv->tx.ndesc; entry++) {
+ ave_desc_write_cmdsts(ndev, AVE_DESCID_TX, entry, 0);
+ ave_desc_write_addr(ndev, AVE_DESCID_TX, entry, 0);
+ }
+ writel(AVE_TXDC_ADDR_START
+ | (((priv->tx.ndesc * priv->desc_size) << 16) & AVE_TXDC_SIZE),
+ priv->base + AVE_TXDC);
+
+ /* initialize Rx work and descriptor */
+ priv->rx.proc_idx = 0;
+ priv->rx.done_idx = 0;
+ for (entry = 0; entry < priv->rx.ndesc; entry++) {
+ if (ave_rxdesc_prepare(ndev, entry))
+ break;
+ }
+ writel(AVE_RXDC0_ADDR_START
+ | (((priv->rx.ndesc * priv->desc_size) << 16) & AVE_RXDC0_SIZE),
+ priv->base + AVE_RXDC0);
+
+ ave_desc_switch(ndev, AVE_DESC_START);
+
+ ave_pfsel_init(ndev);
+ ave_macaddr_init(ndev);
+
+ /* set Rx configuration */
+ /* full duplex, enable pause drop, enalbe flow control */
+ val = AVE_RXCR_RXEN | AVE_RXCR_FDUPEN | AVE_RXCR_DRPEN |
+ AVE_RXCR_FLOCTR | (AVE_MAX_ETHFRAME & AVE_RXCR_MPSIZ_MASK);
+ writel(val, priv->base + AVE_RXCR);
+
+ /* set Tx configuration */
+ /* enable flow control, disable loopback */
+ writel(AVE_TXCR_FLOCTR, priv->base + AVE_TXCR);
+
+ /* enable timer, clear EN,INTM, and mask interval unit(BSCK) */
+ val = readl(priv->base + AVE_IIRQC) & AVE_IIRQC_BSCK;
+ val |= AVE_IIRQC_EN0 | (AVE_INTM_COUNT << 16);
+ writel(val, priv->base + AVE_IIRQC);
+
+ val = AVE_GI_RXIINT | AVE_GI_RXOVF | AVE_GI_TX;
+ ave_irq_restore(ndev, val);
+
+ napi_enable(&priv->napi_rx);
+ napi_enable(&priv->napi_tx);
+
+ phy_start(ndev->phydev);
+ phy_start_aneg(ndev->phydev);
+ netif_start_queue(ndev);
+
+ return 0;
+
+out_free_irq:
+ disable_irq(priv->irq);
+ free_irq(priv->irq, ndev);
+
+ return ret;
+}
+
+static int ave_stop(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ int entry;
+
+ ave_irq_disable_all(ndev);
+ disable_irq(priv->irq);
+ free_irq(priv->irq, ndev);
+
+ netif_tx_disable(ndev);
+ phy_stop(ndev->phydev);
+ napi_disable(&priv->napi_tx);
+ napi_disable(&priv->napi_rx);
+
+ ave_desc_switch(ndev, AVE_DESC_STOP);
+
+ /* free Tx buffer */
+ for (entry = 0; entry < priv->tx.ndesc; entry++) {
+ if (!priv->tx.desc[entry].skbs)
+ continue;
+
+ ave_dma_unmap(ndev, &priv->tx.desc[entry], DMA_TO_DEVICE);
+ dev_kfree_skb_any(priv->tx.desc[entry].skbs);
+ priv->tx.desc[entry].skbs = NULL;
+ }
+ priv->tx.proc_idx = 0;
+ priv->tx.done_idx = 0;
+
+ /* free Rx buffer */
+ for (entry = 0; entry < priv->rx.ndesc; entry++) {
+ if (!priv->rx.desc[entry].skbs)
+ continue;
+
+ ave_dma_unmap(ndev, &priv->rx.desc[entry], DMA_FROM_DEVICE);
+ dev_kfree_skb_any(priv->rx.desc[entry].skbs);
+ priv->rx.desc[entry].skbs = NULL;
+ }
+ priv->rx.proc_idx = 0;
+ priv->rx.done_idx = 0;
+
+ kfree(priv->tx.desc);
+ kfree(priv->rx.desc);
+
+ return 0;
+}
+
+static int ave_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ u32 proc_idx, done_idx, ndesc, cmdsts;
+ int ret, freepkt;
+ dma_addr_t paddr;
+
+ proc_idx = priv->tx.proc_idx;
+ done_idx = priv->tx.done_idx;
+ ndesc = priv->tx.ndesc;
+ freepkt = ((done_idx + ndesc - 1) - proc_idx) % ndesc;
+
+ /* stop queue when not enough entry */
+ if (unlikely(freepkt < 1)) {
+ netif_stop_queue(ndev);
+ return NETDEV_TX_BUSY;
+ }
+
+ /* add padding for short packet */
+ if (skb_put_padto(skb, ETH_ZLEN)) {
+ priv->stats_tx.dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ /* map Tx buffer
+ * Tx buffer set to the Tx descriptor doesn't have any restriction.
+ */
+ ret = ave_dma_map(ndev, &priv->tx.desc[proc_idx],
+ skb->data, skb->len, DMA_TO_DEVICE, &paddr);
+ if (ret) {
+ dev_kfree_skb_any(skb);
+ priv->stats_tx.dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ priv->tx.desc[proc_idx].skbs = skb;
+
+ ave_desc_write_addr(ndev, AVE_DESCID_TX, proc_idx, paddr);
+
+ cmdsts = AVE_STS_OWN | AVE_STS_1ST | AVE_STS_LAST
+ | (skb->len & AVE_STS_PKTLEN_TX_MASK);
+
+ /* set interrupt per AVE_FORCE_TXINTCNT or when queue is stopped */
+ if (!(proc_idx % AVE_FORCE_TXINTCNT) || netif_queue_stopped(ndev))
+ cmdsts |= AVE_STS_INTR;
+
+ /* disable checksum calculation when skb doesn't calurate checksum */
+ if (skb->ip_summed == CHECKSUM_NONE ||
+ skb->ip_summed == CHECKSUM_UNNECESSARY)
+ cmdsts |= AVE_STS_NOCSUM;
+
+ ave_desc_write_cmdsts(ndev, AVE_DESCID_TX, proc_idx, cmdsts);
+
+ priv->tx.proc_idx = (proc_idx + 1) % ndesc;
+
+ return NETDEV_TX_OK;
+}
+
+static int ave_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ return phy_mii_ioctl(ndev->phydev, ifr, cmd);
+}
+
+static void ave_set_rx_mode(struct net_device *ndev)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ struct netdev_hw_addr *hw_adr;
+ int count, mc_cnt = netdev_mc_count(ndev);
+ u32 val;
+ static const u8 v4multi_macadr[6] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const u8 v6multi_macadr[6] = {
+ 0x33, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ /* MAC addr filter enable for promiscious mode */
+ val = readl(priv->base + AVE_RXCR);
+ if (ndev->flags & IFF_PROMISC || !mc_cnt)
+ val &= ~AVE_RXCR_AFEN;
+ else
+ val |= AVE_RXCR_AFEN;
+ writel(val, priv->base + AVE_RXCR);
+
+ /* set all multicast address */
+ if ((ndev->flags & IFF_ALLMULTI) || mc_cnt > AVE_PF_MULTICAST_SIZE) {
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST,
+ v4multi_macadr, 1);
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST + 1,
+ v6multi_macadr, 1);
+ } else {
+ /* stop all multicast filter */
+ for (count = 0; count < AVE_PF_MULTICAST_SIZE; count++)
+ ave_pfsel_stop(ndev, AVE_PFNUM_MULTICAST + count);
+
+ /* set multicast addresses */
+ count = 0;
+ netdev_for_each_mc_addr(hw_adr, ndev) {
+ if (count == mc_cnt)
+ break;
+ ave_pfsel_set_macaddr(ndev, AVE_PFNUM_MULTICAST + count,
+ hw_adr->addr, 6);
+ count++;
+ }
+ }
+}
+
+static void ave_get_stats64(struct net_device *ndev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct ave_private *priv = netdev_priv(ndev);
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_irq(&priv->stats_rx.syncp);
+ stats->rx_packets = priv->stats_rx.packets;
+ stats->rx_bytes = priv->stats_rx.bytes;
+ } while (u64_stats_fetch_retry_irq(&priv->stats_rx.syncp, start));
+
+ do {
+ start = u64_stats_fetch_begin_irq(&priv->stats_tx.syncp);
+ stats->tx_packets = priv->stats_tx.packets;
+ stats->tx_bytes = priv->stats_tx.bytes;
+ } while (u64_stats_fetch_retry_irq(&priv->stats_tx.syncp, start));
+
+ stats->rx_errors = priv->stats_rx.errors;
+ stats->tx_errors = priv->stats_tx.errors;
+ stats->rx_dropped = priv->stats_rx.dropped;
+ stats->tx_dropped = priv->stats_tx.dropped;
+ stats->rx_fifo_errors = priv->stats_rx.fifo_errors;
+ stats->collisions = priv->stats_tx.collisions;
+}
+
+static int ave_set_mac_address(struct net_device *ndev, void *p)
+{
+ int ret = eth_mac_addr(ndev, p);
+
+ if (ret)
+ return ret;
+
+ ave_macaddr_init(ndev);
+
+ return 0;
+}
+
+static const struct net_device_ops ave_netdev_ops = {
+ .ndo_init = ave_init,
+ .ndo_uninit = ave_uninit,
+ .ndo_open = ave_open,
+ .ndo_stop = ave_stop,
+ .ndo_start_xmit = ave_start_xmit,
+ .ndo_do_ioctl = ave_ioctl,
+ .ndo_set_rx_mode = ave_set_rx_mode,
+ .ndo_get_stats64 = ave_get_stats64,
+ .ndo_set_mac_address = ave_set_mac_address,
+};
+
+static int ave_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ave_private *priv;
+ struct net_device *ndev;
+ struct resource *res;
+ const struct ave_soc_data *data;
+ const void *mac_addr;
+ phy_interface_t phy_mode;
+ void __iomem *base;
+ u32 ave_id;
+ u64 dma_mask;
+ int irq, ret;
+ char buf[ETHTOOL_FWVERS_LEN];
+
+ data = of_device_get_match_data(dev);
+ if (WARN_ON(!data))
+ return -EINVAL;
+
+ phy_mode = of_get_phy_mode(np);
+ if (phy_mode < 0) {
+ dev_err(dev, "phy-mode not found\n");
+ return -EINVAL;
+ }
+ if ((!phy_interface_mode_is_rgmii(phy_mode)) &&
+ phy_mode != PHY_INTERFACE_MODE_RMII &&
+ phy_mode != PHY_INTERFACE_MODE_MII) {
+ dev_err(dev, "phy-mode is invalid\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "IRQ not found\n");
+ return irq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ ndev = alloc_etherdev(sizeof(struct ave_private));
+ if (!ndev) {
+ dev_err(dev, "can't allocate ethernet device\n");
+ return -ENOMEM;
+ }
+
+ ndev->netdev_ops = &ave_netdev_ops;
+ ndev->ethtool_ops = &ave_ethtool_ops;
+ SET_NETDEV_DEV(ndev, dev);
+
+ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_RXCSUM);
+ ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_RXCSUM);
+
+ ndev->max_mtu = AVE_MAX_ETHFRAME - (ETH_HLEN + ETH_FCS_LEN);
+
+ mac_addr = of_get_mac_address(np);
+ if (mac_addr)
+ ether_addr_copy(ndev->dev_addr, mac_addr);
+
+ /* if the mac address is invalid, use random mac address */
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ eth_hw_addr_random(ndev);
+ dev_warn(dev, "Using random MAC address: %pM\n",
+ ndev->dev_addr);
+ }
+
+ priv = netdev_priv(ndev);
+ priv->base = base;
+ priv->irq = irq;
+ priv->ndev = ndev;
+ priv->msg_enable = netif_msg_init(-1, AVE_DEFAULT_MSG_ENABLE);
+ priv->phy_mode = phy_mode;
+ priv->data = data;
+
+ if (IS_DESC_64BIT(priv)) {
+ priv->desc_size = AVE_DESC_SIZE_64;
+ priv->tx.daddr = AVE_TXDM_64;
+ priv->rx.daddr = AVE_RXDM_64;
+ dma_mask = DMA_BIT_MASK(64);
+ } else {
+ priv->desc_size = AVE_DESC_SIZE_32;
+ priv->tx.daddr = AVE_TXDM_32;
+ priv->rx.daddr = AVE_RXDM_32;
+ dma_mask = DMA_BIT_MASK(32);
+ }
+ ret = dma_set_mask(dev, dma_mask);
+ if (ret)
+ goto out_free_netdev;
+
+ priv->tx.ndesc = AVE_NR_TXDESC;
+ priv->rx.ndesc = AVE_NR_RXDESC;
+
+ u64_stats_init(&priv->stats_tx.syncp);
+ u64_stats_init(&priv->stats_rx.syncp);
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto out_free_netdev;
+ }
+
+ priv->rst = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(priv->rst)) {
+ ret = PTR_ERR(priv->rst);
+ goto out_free_netdev;
+ }
+
+ priv->mdio = devm_mdiobus_alloc(dev);
+ if (!priv->mdio) {
+ ret = -ENOMEM;
+ goto out_free_netdev;
+ }
+ priv->mdio->priv = ndev;
+ priv->mdio->parent = dev;
+ priv->mdio->read = ave_mdiobus_read;
+ priv->mdio->write = ave_mdiobus_write;
+ priv->mdio->name = "uniphier-mdio";
+ snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "%s-%x",
+ pdev->name, pdev->id);
+
+ /* Register as a NAPI supported driver */
+ netif_napi_add(ndev, &priv->napi_rx, ave_napi_poll_rx, priv->rx.ndesc);
+ netif_tx_napi_add(ndev, &priv->napi_tx, ave_napi_poll_tx,
+ priv->tx.ndesc);
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ dev_err(dev, "failed to register netdevice\n");
+ goto out_del_napi;
+ }
+
+ platform_set_drvdata(pdev, ndev);
+
+ /* get ID and version */
+ ave_id = readl(priv->base + AVE_IDR);
+ ave_hw_read_version(ndev, buf, sizeof(buf));
+
+ dev_info(dev, "Socionext %c%c%c%c Ethernet IP %s (irq=%d, phy=%s)\n",
+ (ave_id >> 24) & 0xff, (ave_id >> 16) & 0xff,
+ (ave_id >> 8) & 0xff, (ave_id >> 0) & 0xff,
+ buf, priv->irq, phy_modes(phy_mode));
+
+ return 0;
+
+out_del_napi:
+ netif_napi_del(&priv->napi_rx);
+ netif_napi_del(&priv->napi_tx);
+out_free_netdev:
+ free_netdev(ndev);
+
+ return ret;
+}
+
+static int ave_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct ave_private *priv = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+ netif_napi_del(&priv->napi_rx);
+ netif_napi_del(&priv->napi_tx);
+ free_netdev(ndev);
+
+ return 0;
+}
+
+static const struct ave_soc_data ave_pro4_data = {
+ .is_desc_64bit = false,
+};
+
+static const struct ave_soc_data ave_pxs2_data = {
+ .is_desc_64bit = false,
+};
+
+static const struct ave_soc_data ave_ld11_data = {
+ .is_desc_64bit = false,
+};
+
+static const struct ave_soc_data ave_ld20_data = {
+ .is_desc_64bit = true,
+};
+
+static const struct of_device_id of_ave_match[] = {
+ {
+ .compatible = "socionext,uniphier-pro4-ave4",
+ .data = &ave_pro4_data,
+ },
+ {
+ .compatible = "socionext,uniphier-pxs2-ave4",
+ .data = &ave_pxs2_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld11-ave4",
+ .data = &ave_ld11_data,
+ },
+ {
+ .compatible = "socionext,uniphier-ld20-ave4",
+ .data = &ave_ld20_data,
+ },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_ave_match);
+
+static struct platform_driver ave_driver = {
+ .probe = ave_probe,
+ .remove = ave_remove,
+ .driver = {
+ .name = "ave",
+ .of_match_table = of_ave_match,
+ },
+};
+module_platform_driver(ave_driver);
+
+MODULE_DESCRIPTION("Socionext UniPhier AVE ethernet driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCH net-next v2 0/5] net: mvpp2: various improvements
From: Antoine Tenart @ 2017-12-11 8:13 UTC (permalink / raw)
To: davem
Cc: Antoine Tenart, gregory.clement, thomas.petazzoni, miquel.raynal,
nadavh, mw, stefanc, ymarkman, netdev, linux-kernel
Hi all,
These patches are sent as a series to avoid any possible conflict, even
though there're not entirely related. I can send them separately if
needed. The series applies on today's net-next tree.
Thanks!
Antoine
Since v1:
- Removed the patch disabling TSO on allocation errors.
Antoine Tenart (4):
net: mvpp2: only free the TSO header buffers when it was allocated
net: mvpp2: align values in ethtool get_coalesce
net: mvpp2: report the tx-usec coalescing information to ethtool
net: mvpp2: adjust the coalescing parameters
Yan Markman (1):
net: mvpp2: split the max ring size from the default one
drivers/net/ethernet/marvell/mvpp2.c | 47 +++++++++++++++++++++---------------
1 file changed, 27 insertions(+), 20 deletions(-)
--
2.14.3
^ permalink raw reply
* [PATCH net-next v2 2/5] net: mvpp2: split the max ring size from the default one
From: Antoine Tenart @ 2017-12-11 8:13 UTC (permalink / raw)
To: davem
Cc: Yan Markman, gregory.clement, thomas.petazzoni, miquel.raynal,
nadavh, mw, stefanc, netdev, linux-kernel, Antoine Tenart
In-Reply-To: <20171211081329.3683-1-antoine.tenart@free-electrons.com>
From: Yan Markman <ymarkman@marvell.com>
The Rx/Tx ring sizes can be adjusted thanks to ethtool given specific
network needs. This commit splits the default ring size from its max
value to allow ethtool to vary the parameters in both ways.
Signed-off-by: Yan Markman <ymarkman@marvell.com>
[Antoine: commit message]
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index f203f0857596..5e88403d2132 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -504,10 +504,12 @@
#define MVPP2_DEFAULT_RXQ 4
/* Max number of Rx descriptors */
-#define MVPP2_MAX_RXD 128
+#define MVPP2_MAX_RXD_MAX 1024
+#define MVPP2_MAX_RXD_DFLT 128
/* Max number of Tx descriptors */
-#define MVPP2_MAX_TXD 1024
+#define MVPP2_MAX_TXD_MAX 2048
+#define MVPP2_MAX_TXD_DFLT 1024
/* Amount of Tx descriptors that can be reserved at once by CPU */
#define MVPP2_CPU_DESC_CHUNK 64
@@ -6836,13 +6838,13 @@ static int mvpp2_check_ringparam_valid(struct net_device *dev,
if (ring->rx_pending == 0 || ring->tx_pending == 0)
return -EINVAL;
- if (ring->rx_pending > MVPP2_MAX_RXD)
- new_rx_pending = MVPP2_MAX_RXD;
+ if (ring->rx_pending > MVPP2_MAX_RXD_MAX)
+ new_rx_pending = MVPP2_MAX_RXD_MAX;
else if (!IS_ALIGNED(ring->rx_pending, 16))
new_rx_pending = ALIGN(ring->rx_pending, 16);
- if (ring->tx_pending > MVPP2_MAX_TXD)
- new_tx_pending = MVPP2_MAX_TXD;
+ if (ring->tx_pending > MVPP2_MAX_TXD_MAX)
+ new_tx_pending = MVPP2_MAX_TXD_MAX;
else if (!IS_ALIGNED(ring->tx_pending, 32))
new_tx_pending = ALIGN(ring->tx_pending, 32);
@@ -7344,8 +7346,8 @@ static void mvpp2_ethtool_get_ringparam(struct net_device *dev,
{
struct mvpp2_port *port = netdev_priv(dev);
- ring->rx_max_pending = MVPP2_MAX_RXD;
- ring->tx_max_pending = MVPP2_MAX_TXD;
+ ring->rx_max_pending = MVPP2_MAX_RXD_MAX;
+ ring->tx_max_pending = MVPP2_MAX_TXD_MAX;
ring->rx_pending = port->rx_ring_size;
ring->tx_pending = port->tx_ring_size;
}
@@ -7792,7 +7794,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
goto err_free_netdev;
}
- dev->tx_queue_len = MVPP2_MAX_TXD;
+ dev->tx_queue_len = MVPP2_MAX_TXD_MAX;
dev->watchdog_timeo = 5 * HZ;
dev->netdev_ops = &mvpp2_netdev_ops;
dev->ethtool_ops = &mvpp2_eth_tool_ops;
@@ -7875,8 +7877,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
mvpp2_port_copy_mac_addr(dev, priv, port_node, &mac_from);
- port->tx_ring_size = MVPP2_MAX_TXD;
- port->rx_ring_size = MVPP2_MAX_RXD;
+ port->tx_ring_size = MVPP2_MAX_TXD_DFLT;
+ port->rx_ring_size = MVPP2_MAX_RXD_DFLT;
SET_NETDEV_DEV(dev, &pdev->dev);
err = mvpp2_port_init(port);
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 4/5] net: mvpp2: report the tx-usec coalescing information to ethtool
From: Antoine Tenart @ 2017-12-11 8:13 UTC (permalink / raw)
To: davem
Cc: Antoine Tenart, gregory.clement, thomas.petazzoni, miquel.raynal,
nadavh, mw, stefanc, ymarkman, netdev, linux-kernel
In-Reply-To: <20171211081329.3683-1-antoine.tenart@free-electrons.com>
This patch adds the tx-usec value to the informations reported to
ethtool by the get_coalesce function.
Suggested-by: Yan Markman <ymarkman@marvell.com>
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 5c16731ee292..aa72109290c3 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -7327,6 +7327,7 @@ static int mvpp2_ethtool_get_coalesce(struct net_device *dev,
c->rx_coalesce_usecs = port->rxqs[0]->time_coal;
c->rx_max_coalesced_frames = port->rxqs[0]->pkts_coal;
c->tx_max_coalesced_frames = port->txqs[0]->done_pkts_coal;
+ c->tx_coalesce_usecs = port->tx_time_coal;
return 0;
}
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 5/5] net: mvpp2: adjust the coalescing parameters
From: Antoine Tenart @ 2017-12-11 8:13 UTC (permalink / raw)
To: davem
Cc: Antoine Tenart, gregory.clement, thomas.petazzoni, miquel.raynal,
nadavh, mw, stefanc, ymarkman, netdev, linux-kernel
In-Reply-To: <20171211081329.3683-1-antoine.tenart@free-electrons.com>
This patch adjust the coalescing parameters to the vendor
recommendations for the PPv2 network controller.
Suggested-by: Yan Markman <ymarkman@marvell.com>
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index aa72109290c3..a19760736b71 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -454,11 +454,11 @@
/* Various constants */
/* Coalescing */
-#define MVPP2_TXDONE_COAL_PKTS_THRESH 15
+#define MVPP2_TXDONE_COAL_PKTS_THRESH 64
#define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL
#define MVPP2_TXDONE_COAL_USEC 1000
#define MVPP2_RX_COAL_PKTS 32
-#define MVPP2_RX_COAL_USEC 100
+#define MVPP2_RX_COAL_USEC 64
/* The two bytes Marvell header. Either contains a special value used
* by Marvell switches when a specific hardware mode is enabled (not
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 1/5] net: mvpp2: only free the TSO header buffers when it was allocated
From: Antoine Tenart @ 2017-12-11 8:13 UTC (permalink / raw)
To: davem
Cc: Antoine Tenart, gregory.clement, thomas.petazzoni, miquel.raynal,
nadavh, mw, stefanc, ymarkman, netdev, linux-kernel
In-Reply-To: <20171211081329.3683-1-antoine.tenart@free-electrons.com>
This patch adds a check to only free the TSO header buffer when its
allocation previously succeeded.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 634b2f41cc9e..f203f0857596 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -5802,6 +5802,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
txq_pcpu->reserved_num = 0;
txq_pcpu->txq_put_index = 0;
txq_pcpu->txq_get_index = 0;
+ txq_pcpu->tso_headers = NULL;
txq_pcpu->stop_threshold = txq->size - MVPP2_MAX_SKB_DESCS;
txq_pcpu->wake_threshold = txq_pcpu->stop_threshold / 2;
@@ -5829,10 +5830,13 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
kfree(txq_pcpu->buffs);
- dma_free_coherent(port->dev->dev.parent,
- txq_pcpu->size * TSO_HEADER_SIZE,
- txq_pcpu->tso_headers,
- txq_pcpu->tso_headers_dma);
+ if (txq_pcpu->tso_headers)
+ dma_free_coherent(port->dev->dev.parent,
+ txq_pcpu->size * TSO_HEADER_SIZE,
+ txq_pcpu->tso_headers,
+ txq_pcpu->tso_headers_dma);
+
+ txq_pcpu->tso_headers = NULL;
}
if (txq->descs)
--
2.14.3
^ permalink raw reply related
* [PATCH net-next v2 3/5] net: mvpp2: align values in ethtool get_coalesce
From: Antoine Tenart @ 2017-12-11 8:13 UTC (permalink / raw)
To: davem
Cc: Antoine Tenart, gregory.clement, thomas.petazzoni, miquel.raynal,
nadavh, mw, stefanc, ymarkman, netdev, linux-kernel
In-Reply-To: <20171211081329.3683-1-antoine.tenart@free-electrons.com>
Cosmetic patch aligning values in the ethtool get_coalesce function.
This patch do not modify in anyway the driver's behaviour.
Signed-off-by: Antoine Tenart <antoine.tenart@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 5e88403d2132..5c16731ee292 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -7324,9 +7324,9 @@ static int mvpp2_ethtool_get_coalesce(struct net_device *dev,
{
struct mvpp2_port *port = netdev_priv(dev);
- c->rx_coalesce_usecs = port->rxqs[0]->time_coal;
- c->rx_max_coalesced_frames = port->rxqs[0]->pkts_coal;
- c->tx_max_coalesced_frames = port->txqs[0]->done_pkts_coal;
+ c->rx_coalesce_usecs = port->rxqs[0]->time_coal;
+ c->rx_max_coalesced_frames = port->rxqs[0]->pkts_coal;
+ c->tx_max_coalesced_frames = port->txqs[0]->done_pkts_coal;
return 0;
}
--
2.14.3
^ permalink raw reply related
* [PATCH net] tcp md5sig: Use skb's saddr when replying to an incoming segment
From: Christoph Paasch @ 2017-12-11 8:05 UTC (permalink / raw)
To: David Miller; +Cc: netdev
The MD5-key that belongs to a connection is identified by the peer's
IP-address. When we are in tcp_v4(6)_reqsk_send_ack(), we are replying
to an incoming segment from tcp_check_req() that failed the seq-number
checks.
Thus, to find the correct key, we need to use the skb's saddr and not
the daddr.
This bug seems to have been there since quite a while, but probably got
unnoticed because the consequences are not catastrophic. We will call
tcp_v4_reqsk_send_ack only to send a challenge-ACK back to the peer,
thus the connection doesn't really fail.
Fixes: 9501f9722922 ("tcp md5sig: Let the caller pass appropriate key for tcp_v{4,6}_do_calc_md5_hash().")
Signed-off-by: Christoph Paasch <cpaasch@apple.com>
---
net/ipv4/tcp_ipv4.c | 2 +-
net/ipv6/tcp_ipv6.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 77ea45da0fe9..94e28350f420 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -848,7 +848,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
tcp_time_stamp_raw() + tcp_rsk(req)->ts_off,
req->ts_recent,
0,
- tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr,
+ tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->saddr,
AF_INET),
inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0,
ip_hdr(skb)->tos);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 1f04ec0e4a7a..7178476b3d2f 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -994,7 +994,7 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
tcp_time_stamp_raw() + tcp_rsk(req)->ts_off,
req->ts_recent, sk->sk_bound_dev_if,
- tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
+ tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr),
0, 0);
}
--
2.15.0
^ permalink raw reply related
* Re: Linux 4.15-rc3 (uml + bpf_perf_event.h)
From: Richard Weinberger @ 2017-12-11 8:32 UTC (permalink / raw)
To: Randy Dunlap, netdev@vger.kernel.org
Cc: Linus Torvalds, Linux Kernel Mailing List
In-Reply-To: <4a55b480-a35b-1432-95d6-079857bceca5@infradead.org>
Randy,
Am Montag, 11. Dezember 2017, 03:42:12 CET schrieb Randy Dunlap:
> On 12/10/2017 06:08 PM, Linus Torvalds wrote:
> > Another week, another rc.
>
> um (uml) won't build on i386 or x86_64:
>
> CC init/main.o
> In file included from ../include/linux/perf_event.h:18:0,
> from ../include/linux/trace_events.h:10,
> from ../include/trace/syscall.h:7,
> from ../include/linux/syscalls.h:82,
> from ../init/main.c:20:
> ../include/uapi/linux/bpf_perf_event.h:11:32: fatal error:
> asm/bpf_perf_event.h: No such file or directory #include
> <asm/bpf_perf_event.h>
> ^
> compilation terminated.
> ../scripts/Makefile.build:310: recipe for target 'init/main.o' failed
>
How do you trigger that build failure?
Can you share your .config?
Thanks,
//richard
--
sigma star gmbh - Eduard-Bodem-Gasse 6 - 6020 Innsbruck - Austria
ATU66964118 - FN 374287y
^ permalink raw reply
* [PATCH] Revert "ravb: add workaround for clock when resuming with WoL enabled"
From: Geert Uytterhoeven @ 2017-12-11 8:54 UTC (permalink / raw)
To: Sergei Shtylyov, David S . Miller, Niklas Söderlund
Cc: netdev, linux-renesas-soc, Geert Uytterhoeven
This reverts commit fbf3d034f2ff6264183cfa6845770e8cc2a986c8.
As of commit 560869100b99a3da ("clk: renesas: cpg-mssr: Restore module
clocks during resume"), the workaround is no longer needed.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/net/ethernet/renesas/ravb_main.c | 27 ++-------------------------
1 file changed, 2 insertions(+), 25 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 2b962d349f5f415b..009780df664b4a09 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2308,32 +2308,9 @@ static int __maybe_unused ravb_resume(struct device *dev)
struct ravb_private *priv = netdev_priv(ndev);
int ret = 0;
- if (priv->wol_enabled) {
- /* Reduce the usecount of the clock to zero and then
- * restore it to its original value. This is done to force
- * the clock to be re-enabled which is a workaround
- * for renesas-cpg-mssr driver which do not enable clocks
- * when resuming from PSCI suspend/resume.
- *
- * Without this workaround the driver fails to communicate
- * with the hardware if WoL was enabled when the system
- * entered PSCI suspend. This is due to that if WoL is enabled
- * we explicitly keep the clock from being turned off when
- * suspending, but in PSCI sleep power is cut so the clock
- * is disabled anyhow, the clock driver is not aware of this
- * so the clock is not turned back on when resuming.
- *
- * TODO: once the renesas-cpg-mssr suspend/resume is working
- * this clock dance should be removed.
- */
- clk_disable(priv->clk);
- clk_disable(priv->clk);
- clk_enable(priv->clk);
- clk_enable(priv->clk);
-
- /* Set reset mode to rearm the WoL logic */
+ /* If WoL is enabled set reset mode to rearm the WoL logic */
+ if (priv->wol_enabled)
ravb_write(ndev, CCC_OPC_RESET, CCC);
- }
/* All register have been reset to default values.
* Restore all registers which where setup at probe time and
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v3 32/33] irqchip: Andestech Internal Vector Interrupt Controller driver
From: Marc Zyngier @ 2017-12-11 9:16 UTC (permalink / raw)
To: Greentime Hu, greentime-MUIXKm3Oiri1Z/+hSey0Gg,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
linux-arch-u79uwXL29TY76Z2rM5mHXA, tglx-hfZtesqFncYOwBW4kG4KsQ,
jason-NLaQJdtUoK4Be96aLqz0jA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
netdev-u79uwXL29TY76Z2rM5mHXA, deanbo422-Re5JQEeQqe8AvxtiuMwx3w,
devicetree-u79uwXL29TY76Z2rM5mHXA,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
dhowells-H+wXaHxf7aLQT0dZR+AlfA, will.deacon-5wv7dgnIgG8,
daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
geert.uytterhoeven-Re5JQEeQqe8AvxtiuMwx3w,
linus.walleij-QSEj5FYQhm4dnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
greg-U8xfFu+wG4EAvxtiuMwx3w
Cc: Rick Chen
In-Reply-To: <4fb7bd1cd2619287061fd68a38a774c8aef7dbe9.1512723245.git.green.hu-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On 08/12/17 09:12, Greentime Hu wrote:
> From: Greentime Hu <greentime-MUIXKm3Oiri1Z/+hSey0Gg@public.gmane.org>
>
> This patch adds the Andestech Internal Vector Interrupt Controller
> driver. You can find the spec here. Ch4.9 of AndeStar SPA V3 Manual.
> http://www.andestech.com/product.php?cls=9
>
> Signed-off-by: Rick Chen <rick-MUIXKm3Oiri1Z/+hSey0Gg@public.gmane.org>
> Signed-off-by: Greentime Hu <greentime-MUIXKm3Oiri1Z/+hSey0Gg@public.gmane.org>
Reviewed-by: Marc Zyngier <marc.zyngier-5wv7dgnIgG8@public.gmane.org>
Once there is an agreement on this series being fit for mainline, let me
know how you want to get this merged (either as a whole series, or with
this driver going through the irq tree).
Thanks,
M.
--
Jazz is not dead. It just smells funny...
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH][netfilter-next] netfilter: conntrack: make struct nf_conntrack_l4proto_gre4 static
From: Florian Westphal @ 2017-12-11 9:18 UTC (permalink / raw)
To: Colin King
Cc: Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
David S . Miller, netfilter-devel, coreteam, netdev,
kernel-janitors, linux-kernel
In-Reply-To: <20171210233255.15009-1-colin.king@canonical.com>
Colin King <colin.king@canonical.com> wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> The structure nf_conntrack_l4proto_gre4 is local to the source and does
> not need to be in global scope, so make it static.
This bug was added in
commit b9679a9fd3a7d36ea3deb2864a00cc413c5aae28
netfilter: conntrack: l4 protocol trackers can be const
> -struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = {
> +static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = {
This should be 'static const'.
^ permalink raw reply
* Re: [PATCH net-next v5 2/2] net: ethernet: socionext: add AVE ethernet driver
From: Philippe Ombredanne @ 2017-12-11 9:19 UTC (permalink / raw)
To: Kunihiko Hayashi
Cc: David S. Miller, netdev, Andrew Lunn, Florian Fainelli,
Rob Herring, Mark Rutland,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE, LKML,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Masahiro Yamada, Masami Hiramatsu, Jassi Brar
In-Reply-To: <1512979049-15930-3-git-send-email-hayashi.kunihiko@socionext.com>
Dear Kunihiko-san,
On Mon, Dec 11, 2017 at 8:57 AM, Kunihiko Hayashi
<hayashi.kunihiko@socionext.com> wrote:
> The UniPhier platform from Socionext provides the AVE ethernet
> controller that includes MAC and MDIO bus supporting RGMII/RMII
> modes. The controller is named AVE.
>
> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>
[...]
> --- /dev/null
> +++ b/drivers/net/ethernet/socionext/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
You are correctly using SPDX ids here....
> +obj-$(CONFIG_SNI_AVE) += sni_ave.o
> diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c
> new file mode 100644
> index 0000000..7b293c2
> --- /dev/null
> +++ b/drivers/net/ethernet/socionext/sni_ave.c
> @@ -0,0 +1,1744 @@
> +/**
> + * sni_ave.c - Socionext UniPhier AVE ethernet driver
> + *
> + * Copyright 2014 Panasonic Corporation
> + * Copyright 2015-2017 Socionext Inc.
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 of
> + * the License as published by the Free Software Foundation.
> + *
> + * 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.
> + */
... then I guess you could also use them here, replacing at least 7
lines of boilerplate by a single id line?
> +// SDPX-License-Identifier: GPL-2.0
And if you go C++ style all the way, this could be even more compact:
> +// SDPX-License-Identifier: GPL-2.0
> +// sni_ave.c - Socionext UniPhier AVE ethernet driver
> +// Copyright 2014 Panasonic Corporation
> +// Copyright 2015-2017 Socionext Inc.
Thank you for your kind consideration!
--
Cordially
Philippe Ombredanne
^ permalink raw reply
* pull-request: mac80211 2017-12-11
From: Johannes Berg @ 2017-12-11 9:52 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-wireless
Hi Dave,
Three fixes, two related to build issues with the new regdb stuff,
and one for some patch overlap problem that caused locking to be
missing which in turn caused lots of warnings.
Please pull and let me know if there's any problem.
Thanks,
johannes
The following changes since commit ccab371f746abca05a599d074cb3b95a549ef590:
Merge branch 'sfp-phylink-fixes' (2017-12-01 15:18:42 -0500)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git tags/mac80211-for-davem-2017-12-11
for you to fetch changes up to 0afe9d4ab9d40c281bdcdd118661fe8e4bdcef18:
mac80211: fix locking in ieee80211_sta_tear_down_BA_sessions (2017-12-11 10:50:00 +0100)
----------------------------------------------------------------
Three fixes:
* for certificate C file generation, don't use hexdump as it's
not always installed by default, use pure posix instead (od/sed)
* for certificate C file generation, don't write the file if
anything fails, so the build abort will not cause a bad build
upon a second attempt
* fix locking in ieee80211_sta_tear_down_BA_sessions() which had
been causing lots of locking warnings
----------------------------------------------------------------
Johannes Berg (3):
wireless: replace usage of hexdump with od/sed
wireless: don't write C files on failures
mac80211: fix locking in ieee80211_sta_tear_down_BA_sessions
net/mac80211/ht.c | 5 ++---
net/wireless/Makefile | 48 ++++++++++++++++++++++++++++++++++++++----------
2 files changed, 40 insertions(+), 13 deletions(-)
^ permalink raw reply
* [PATCH v1] Bluetooth: Utilize %*ph specifier
From: Andy Shevchenko @ 2017-12-11 10:10 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA, David S. Miller,
netdev-u79uwXL29TY76Z2rM5mHXA
Cc: Andy Shevchenko
Instead of open coding byte-by-byte printing, re-use %*ph specifier.
Signed-off-by: Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
net/bluetooth/hci_debugfs.c | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c
index 63df63ebfb24..e204bfdb5ba2 100644
--- a/net/bluetooth/hci_debugfs.c
+++ b/net/bluetooth/hci_debugfs.c
@@ -106,21 +106,10 @@ static int features_show(struct seq_file *f, void *ptr)
u8 p;
hci_dev_lock(hdev);
- for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) {
- seq_printf(f, "%2u: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
- "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", p,
- hdev->features[p][0], hdev->features[p][1],
- hdev->features[p][2], hdev->features[p][3],
- hdev->features[p][4], hdev->features[p][5],
- hdev->features[p][6], hdev->features[p][7]);
- }
+ for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++)
+ seq_printf(f, "%2u: %8ph\n", p, hdev->features[p]);
if (lmp_le_capable(hdev))
- seq_printf(f, "LE: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
- "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
- hdev->le_features[0], hdev->le_features[1],
- hdev->le_features[2], hdev->le_features[3],
- hdev->le_features[4], hdev->le_features[5],
- hdev->le_features[6], hdev->le_features[7]);
+ seq_printf(f, "LE: %8ph\n", hdev->le_features);
hci_dev_unlock(hdev);
return 0;
--
2.15.0
^ permalink raw reply related
* Re: Linux 4.15-rc3 (uml + bpf_perf_event.h)
From: Daniel Borkmann @ 2017-12-11 10:19 UTC (permalink / raw)
To: Richard Weinberger, Randy Dunlap, netdev@vger.kernel.org
Cc: Linus Torvalds, Linux Kernel Mailing List, alexei.starovoitov,
brueckner
In-Reply-To: <7534692.EB8JgYtGIt@blindfold>
Hi Randy, hi Richard, [ +Hendrik for c895f6f703ad7dd2f ]
On 12/11/2017 09:32 AM, Richard Weinberger wrote:
> Randy,
>
> Am Montag, 11. Dezember 2017, 03:42:12 CET schrieb Randy Dunlap:
>> On 12/10/2017 06:08 PM, Linus Torvalds wrote:
>>> Another week, another rc.
>>
>> um (uml) won't build on i386 or x86_64:
>>
>> CC init/main.o
>> In file included from ../include/linux/perf_event.h:18:0,
>> from ../include/linux/trace_events.h:10,
>> from ../include/trace/syscall.h:7,
>> from ../include/linux/syscalls.h:82,
>> from ../init/main.c:20:
>> ../include/uapi/linux/bpf_perf_event.h:11:32: fatal error:
>> asm/bpf_perf_event.h: No such file or directory #include
>> <asm/bpf_perf_event.h>
>> ^
>> compilation terminated.
>> ../scripts/Makefile.build:310: recipe for target 'init/main.o' failed
>
> How do you trigger that build failure?
> Can you share your .config?
Hmm, too bad kbuild bot doesn't catch issues on uml. I'm not too familiar
with uml, but looks like it's the only special case where there's no
arch/um/include/uapi/asm/. What is the usual convention to pull in such
headers in this case? Something like the below, would that fix it for you?
Thanks for your help,
Daniel
arch/um/include/asm/bpf_perf_event.h | 1 +
include/asm-generic/bpf_perf_event.h | 1 +
2 files changed, 2 insertions(+)
create mode 100644 arch/um/include/asm/bpf_perf_event.h
create mode 100644 include/asm-generic/bpf_perf_event.h
diff --git a/arch/um/include/asm/bpf_perf_event.h b/arch/um/include/asm/bpf_perf_event.h
new file mode 100644
index 0000000..3097758
--- /dev/null
+++ b/arch/um/include/asm/bpf_perf_event.h
@@ -0,0 +1 @@
+#include <asm-generic/bpf_perf_event.h>
diff --git a/include/asm-generic/bpf_perf_event.h b/include/asm-generic/bpf_perf_event.h
new file mode 100644
index 0000000..67112e5
--- /dev/null
+++ b/include/asm-generic/bpf_perf_event.h
@@ -0,0 +1 @@
+#include <uapi/asm-generic/bpf_perf_event.h>
--
2.9.5
^ permalink raw reply related
* Re: [PATCH net-next v3 1/2] bpf/tracing: allow user space to query prog array on the same tp
From: Peter Zijlstra @ 2017-12-11 11:17 UTC (permalink / raw)
To: Yonghong Song; +Cc: rostedt, ast, daniel, kafai, netdev, kernel-team
In-Reply-To: <20171206220746.4038383-2-yhs@fb.com>
On Wed, Dec 06, 2017 at 02:07:45PM -0800, Yonghong Song wrote:
> Commit e87c6bc3852b ("bpf: permit multiple bpf attachments
> for a single perf event") added support to attach multiple
> bpf programs to a single perf event.
> Although this provides flexibility, users may want to know
> what other bpf programs attached to the same tp interface.
> Besides getting visibility for the underlying bpf system,
> such information may also help consolidate multiple bpf programs,
> understand potential performance issues due to a large array,
> and debug (e.g., one bpf program which overwrites return code
> may impact subsequent program results).
>
> Commit 2541517c32be ("tracing, perf: Implement BPF programs
> attached to kprobes") utilized the existing perf ioctl
> interface and added the command PERF_EVENT_IOC_SET_BPF
> to attach a bpf program to a tracepoint. This patch adds a new
> ioctl command, given a perf event fd, to query the bpf program
> array attached to the same perf tracepoint event.
>
> The new uapi ioctl command:
> PERF_EVENT_IOC_QUERY_BPF
>
> The new uapi/linux/perf_event.h structure:
> struct perf_event_query_bpf {
> __u32 ids_len;
> __u32 prog_cnt;
> __u32 ids[0];
> };
>
> User space provides buffer "ids" for kernel to copy to.
> When returning from the kernel, the number of available
> programs in the array is set in "prog_cnt".
>
> The usage:
struct perf_event_query_bpf *query =
malloc(sizeof(*query) + sizeof(u32) * ids_len);
query->ids_len = ids_len;
err = ioctl(pmu_efd, PERF_EVENT_IOC_QUERY_BPF, query);
> if (err == 0) {
> /* query.prog_cnt is the number of available progs,
> * number of progs in ids: (ids_len == 0) ? 0 : query.prog_cnt
> */
> } else if (errno == ENOSPC) {
> /* query.ids_len number of progs copied,
> * query.prog_cnt is the number of available progs
> */
> } else {
> /* other errors */
> }
>
> Signed-off-by: Yonghong Song <yhs@fb.com>
Yes this looks much better, thanks!
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
^ permalink raw reply
* [PATCH net-next v4 0/5] Introduce NETIF_F_GRO_HW
From: Michael Chan @ 2017-12-11 11:41 UTC (permalink / raw)
To: davem; +Cc: netdev, andrew.gospodarek
Introduce NETIF_F_GRO_HW feature flag and convert drivers that support
hardware GRO to use the new flag.
v4:
- more changes requested by Alexander Duyck:
- check GRO_HW/GRO dependency in drivers's ndo_fix_features().
- Reverse the order of RXCSUM and GRO_HW dependency check in
netdev_fix_features().
- No propagation in netdev_disable_gro_hw().
v3:
- Let driver's ndo_fix_features() disable NETIF_F_LRO when NETIF_F_GRO_HW
is set instead of doing it in common netdev_fix_features().
v2:
- NETIF_F_GRO_HW flag propagation between upper and lower devices not
required (see patch 1).
- NETIF_F_GRO_HW depends on NETIF_F_GRO and NETIF_F_RXCSUM.
- Add dev_disable_gro_hw() to disable GRO_HW for generic XDP.
- Use ndo_fix_features() on all 3 drivers to drop GRO_HW when it is not
supported
Michael Chan (5):
net: Introduce NETIF_F_GRO_HW.
net: Disable GRO_HW when generic XDP is installed on a device.
bnxt_en: Use NETIF_F_GRO_HW.
bnx2x: Use NETIF_F_GRO_HW.
qede: Use NETIF_F_GRO_HW.
Documentation/networking/netdev-features.txt | 8 +++++++
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 19 ++++++++++------
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 4 +++-
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 27 +++++++++++++++++------
drivers/net/ethernet/qlogic/qede/qede.h | 2 ++
drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 3 +++
drivers/net/ethernet/qlogic/qede/qede_filter.c | 21 ++++++++++++------
drivers/net/ethernet/qlogic/qede/qede_main.c | 17 +++++---------
include/linux/netdev_features.h | 3 +++
net/core/dev.c | 28 ++++++++++++++++++++++++
net/core/ethtool.c | 1 +
11 files changed, 100 insertions(+), 33 deletions(-)
--
1.8.3.1
^ permalink raw reply
* [PATCH net-next v4 1/5] net: Introduce NETIF_F_GRO_HW.
From: Michael Chan @ 2017-12-11 11:41 UTC (permalink / raw)
To: davem; +Cc: netdev, andrew.gospodarek, Ariel Elior, everest-linux-l2
In-Reply-To: <1512992470-28861-1-git-send-email-michael.chan@broadcom.com>
Introduce NETIF_F_GRO_HW feature flag for NICs that support hardware
GRO. With this flag, we can now independently turn on or off hardware
GRO when GRO is on. Previously, drivers were using NETIF_F_GRO to
control hardware GRO and so it cannot be independently turned on or
off without affecting GRO.
Hardware GRO (just like GRO) guarantees that packets can be re-segmented
by TSO/GSO to reconstruct the original packet stream. Logically,
GRO_HW should depend on GRO since it a subset, but we will let
individual drivers enforce this dependency as they see fit.
Since NETIF_F_GRO is not propagated between upper and lower devices,
NETIF_F_GRO_HW should follow suit since it is a subset of GRO. In other
words, a lower device can independent have GRO/GRO_HW enabled or disabled
and no feature propagation is required. This will preserve the current
GRO behavior. This can be changed later if we decide to propagate GRO/
GRO_HW/RXCSUM from upper to lower devices.
Cc: Ariel Elior <Ariel.Elior@cavium.com>
Cc: everest-linux-l2@cavium.com
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
Documentation/networking/netdev-features.txt | 8 ++++++++
include/linux/netdev_features.h | 3 +++
net/core/dev.c | 10 ++++++++++
net/core/ethtool.c | 1 +
4 files changed, 22 insertions(+)
diff --git a/Documentation/networking/netdev-features.txt b/Documentation/networking/netdev-features.txt
index 7413eb0..8f36527 100644
--- a/Documentation/networking/netdev-features.txt
+++ b/Documentation/networking/netdev-features.txt
@@ -163,3 +163,11 @@ This requests that the NIC receive all possible frames, including errored
frames (such as bad FCS, etc). This can be helpful when sniffing a link with
bad packets on it. Some NICs may receive more packets if also put into normal
PROMISC mode.
+
+* rx-gro-hw
+
+This requests that the NIC enables Hardware GRO (generic receive offload).
+Hardware GRO is basically the exact reverse of TSO, and is generally
+stricter than Hardware LRO. A packet stream merged by Hardware GRO must
+be re-segmentable by GSO or TSO back to the exact original packet stream.
+Hardware GRO is dependent on GRO and RXCSUM.
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index b1b0ca7..db84c51 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -78,6 +78,8 @@ enum {
NETIF_F_HW_ESP_TX_CSUM_BIT, /* ESP with TX checksum offload */
NETIF_F_RX_UDP_TUNNEL_PORT_BIT, /* Offload of RX port for UDP tunnels */
+ NETIF_F_GRO_HW_BIT, /* Hardware Generic receive offload */
+
/*
* Add your fresh new feature above and remember to update
* netdev_features_strings[] in net/core/ethtool.c and maybe
@@ -97,6 +99,7 @@ enum {
#define NETIF_F_FRAGLIST __NETIF_F(FRAGLIST)
#define NETIF_F_FSO __NETIF_F(FSO)
#define NETIF_F_GRO __NETIF_F(GRO)
+#define NETIF_F_GRO_HW __NETIF_F(GRO_HW)
#define NETIF_F_GSO __NETIF_F(GSO)
#define NETIF_F_GSO_ROBUST __NETIF_F(GSO_ROBUST)
#define NETIF_F_HIGHDMA __NETIF_F(HIGHDMA)
diff --git a/net/core/dev.c b/net/core/dev.c
index 8aa2f70..bf0149e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7424,6 +7424,16 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,
features &= ~dev->gso_partial_features;
}
+ if (!(features & NETIF_F_RXCSUM)) {
+ /* NETIF_F_GRO_HW implies doing RXCSUM. If the user does not
+ * want to enable RXCSUM, logically, we should disable GRO_HW.
+ */
+ if (features & NETIF_F_GRO_HW) {
+ netdev_dbg(dev, "Dropping NETIF_F_GRO_HW since no RXCSUM feature.\n");
+ features &= ~NETIF_F_GRO_HW;
+ }
+ }
+
return features;
}
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index f8fcf45..50a7920 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -73,6 +73,7 @@ int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
[NETIF_F_LLTX_BIT] = "tx-lockless",
[NETIF_F_NETNS_LOCAL_BIT] = "netns-local",
[NETIF_F_GRO_BIT] = "rx-gro",
+ [NETIF_F_GRO_HW_BIT] = "rx-gro-hw",
[NETIF_F_LRO_BIT] = "rx-lro",
[NETIF_F_TSO_BIT] = "tx-tcp-segmentation",
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next v4 2/5] net: Disable GRO_HW when generic XDP is installed on a device.
From: Michael Chan @ 2017-12-11 11:41 UTC (permalink / raw)
To: davem; +Cc: netdev, andrew.gospodarek, Ariel Elior, everest-linux-l2
In-Reply-To: <1512992470-28861-1-git-send-email-michael.chan@broadcom.com>
Hardware should not aggregate any packets when generic XDP is installed.
Cc: Ariel Elior <Ariel.Elior@cavium.com>
Cc: everest-linux-l2@cavium.com
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
net/core/dev.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index bf0149e..5e47779 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1542,6 +1542,23 @@ void dev_disable_lro(struct net_device *dev)
}
EXPORT_SYMBOL(dev_disable_lro);
+/**
+ * dev_disable_gro_hw - disable HW Generic Receive Offload on a device
+ * @dev: device
+ *
+ * Disable HW Generic Receive Offload (GRO_HW) on a net device. Must be
+ * called under RTNL. This is needed if Generic XDP is installed on
+ * the device.
+ */
+static void dev_disable_gro_hw(struct net_device *dev)
+{
+ dev->wanted_features &= ~NETIF_F_GRO_HW;
+ netdev_update_features(dev);
+
+ if (unlikely(dev->features & NETIF_F_GRO_HW))
+ netdev_WARN(dev, "failed to disable GRO_HW!\n");
+}
+
static int call_netdevice_notifier(struct notifier_block *nb, unsigned long val,
struct net_device *dev)
{
@@ -4564,6 +4581,7 @@ static int generic_xdp_install(struct net_device *dev, struct netdev_bpf *xdp)
} else if (new && !old) {
static_key_slow_inc(&generic_xdp_needed);
dev_disable_lro(dev);
+ dev_disable_gro_hw(dev);
}
break;
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next v4 3/5] bnxt_en: Use NETIF_F_GRO_HW.
From: Michael Chan @ 2017-12-11 11:41 UTC (permalink / raw)
To: davem; +Cc: netdev, andrew.gospodarek
In-Reply-To: <1512992470-28861-1-git-send-email-michael.chan@broadcom.com>
Advertise NETIF_F_GRO_HW in hw_features if hardware GRO is supported.
In bnxt_fix_features(), disable GRO_HW and LRO if current hardware
configuration does not allow it. GRO_HW depends on GRO. GRO_HW is
also mutually exclusive with LRO. XDP setup will now rely on
bnxt_fix_features() to turn off aggregation. During chip init, turn on
or off hardware GRO based on NETIF_F_GRO_HW in features flag.
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 1d865ae..9efbdc6 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -2755,7 +2755,7 @@ void bnxt_set_tpa_flags(struct bnxt *bp)
return;
if (bp->dev->features & NETIF_F_LRO)
bp->flags |= BNXT_FLAG_LRO;
- if (bp->dev->features & NETIF_F_GRO)
+ else if (bp->dev->features & NETIF_F_GRO_HW)
bp->flags |= BNXT_FLAG_GRO;
}
@@ -2843,10 +2843,10 @@ int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode)
min_t(u16, bp->max_mtu, BNXT_MAX_PAGE_MODE_MTU);
bp->flags &= ~BNXT_FLAG_AGG_RINGS;
bp->flags |= BNXT_FLAG_NO_AGG_RINGS | BNXT_FLAG_RX_PAGE_MODE;
- bp->dev->hw_features &= ~NETIF_F_LRO;
- bp->dev->features &= ~NETIF_F_LRO;
bp->rx_dir = DMA_BIDIRECTIONAL;
bp->rx_skb_func = bnxt_rx_page_skb;
+ /* Disable LRO or GRO_HW */
+ netdev_update_features(bp->dev);
} else {
bp->dev->max_mtu = bp->max_mtu;
bp->flags &= ~BNXT_FLAG_RX_PAGE_MODE;
@@ -6788,6 +6788,15 @@ static netdev_features_t bnxt_fix_features(struct net_device *dev,
if ((features & NETIF_F_NTUPLE) && !bnxt_rfs_capable(bp))
features &= ~NETIF_F_NTUPLE;
+ if (bp->flags & BNXT_FLAG_NO_AGG_RINGS)
+ features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
+
+ if (!(features & NETIF_F_GRO))
+ features &= ~NETIF_F_GRO_HW;
+
+ if (features & NETIF_F_GRO_HW)
+ features &= ~NETIF_F_LRO;
+
/* Both CTAG and STAG VLAN accelaration on the RX side have to be
* turned on or off together.
*/
@@ -6821,9 +6830,9 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)
bool update_tpa = false;
flags &= ~BNXT_FLAG_ALL_CONFIG_FEATS;
- if ((features & NETIF_F_GRO) && !BNXT_CHIP_TYPE_NITRO_A0(bp))
+ if (features & NETIF_F_GRO_HW)
flags |= BNXT_FLAG_GRO;
- if (features & NETIF_F_LRO)
+ else if (features & NETIF_F_LRO)
flags |= BNXT_FLAG_LRO;
if (bp->flags & BNXT_FLAG_NO_AGG_RINGS)
@@ -7924,8 +7933,8 @@ static int bnxt_get_dflt_rings(struct bnxt *bp, int *max_rx, int *max_tx,
if (rc)
return rc;
bp->flags |= BNXT_FLAG_NO_AGG_RINGS;
- bp->dev->hw_features &= ~NETIF_F_LRO;
- bp->dev->features &= ~NETIF_F_LRO;
+ bp->dev->hw_features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
+ bp->dev->features &= ~(NETIF_F_LRO | NETIF_F_GRO_HW);
bnxt_set_ring_params(bp);
}
@@ -8108,7 +8117,11 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->vlan_features = dev->hw_features | NETIF_F_HIGHDMA;
dev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX;
+ if (!BNXT_CHIP_TYPE_NITRO_A0(bp))
+ dev->hw_features |= NETIF_F_GRO_HW;
dev->features |= dev->hw_features | NETIF_F_HIGHDMA;
+ if (dev->features & NETIF_F_GRO_HW)
+ dev->features &= ~NETIF_F_LRO;
dev->priv_flags |= IFF_UNICAST_FLT;
#ifdef CONFIG_BNXT_SRIOV
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next v4 4/5] bnx2x: Use NETIF_F_GRO_HW.
From: Michael Chan @ 2017-12-11 11:41 UTC (permalink / raw)
To: davem; +Cc: netdev, andrew.gospodarek, Ariel Elior, everest-linux-l2
In-Reply-To: <1512992470-28861-1-git-send-email-michael.chan@broadcom.com>
Advertise NETIF_F_GRO_HW and turn on TPA_MODE_GRO when NETIF_F_GRO_HW
is set. Disable NETIF_F_GRO_HW in bnx2x_fix_features() if the MTU
does not support TPA_MODE_GRO or GRO is not set. bnx2x_change_mtu() also
needs to disable NETIF_F_GRO_HW if the MTU does not support it.
Cc: Ariel Elior <Ariel.Elior@cavium.com>
Cc: everest-linux-l2@cavium.com
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 19 ++++++++++++-------
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 4 +++-
2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 4c739d5..f9b18a7 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -2482,8 +2482,7 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index)
*/
if (bp->dev->features & NETIF_F_LRO)
fp->mode = TPA_MODE_LRO;
- else if (bp->dev->features & NETIF_F_GRO &&
- bnx2x_mtu_allows_gro(bp->dev->mtu))
+ else if (bp->dev->features & NETIF_F_GRO_HW)
fp->mode = TPA_MODE_GRO;
else
fp->mode = TPA_MODE_DISABLED;
@@ -4874,6 +4873,9 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
*/
dev->mtu = new_mtu;
+ if (!bnx2x_mtu_allows_gro(new_mtu))
+ dev->features &= ~NETIF_F_GRO_HW;
+
if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg))
SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS);
@@ -4907,6 +4909,10 @@ netdev_features_t bnx2x_fix_features(struct net_device *dev,
features &= ~NETIF_F_LRO;
features &= ~NETIF_F_GRO;
}
+ if (!(features & NETIF_F_GRO) || !bnx2x_mtu_allows_gro(dev->mtu))
+ features &= ~NETIF_F_GRO_HW;
+ if (features & NETIF_F_GRO_HW)
+ features &= ~NETIF_F_LRO;
return features;
}
@@ -4933,13 +4939,12 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
}
}
- /* if GRO is changed while LRO is enabled, don't force a reload */
- if ((changes & NETIF_F_GRO) && (features & NETIF_F_LRO))
- changes &= ~NETIF_F_GRO;
+ /* Don't care about GRO changes */
+ changes &= ~NETIF_F_GRO;
/* if GRO is changed while HW TPA is off, don't force a reload */
- if ((changes & NETIF_F_GRO) && bp->disable_tpa)
- changes &= ~NETIF_F_GRO;
+ if ((changes & NETIF_F_GRO_HW) && bp->disable_tpa)
+ changes &= ~NETIF_F_GRO_HW;
if (changes)
bnx2x_reload = true;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 91e2a75..1c7f821 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -13273,7 +13273,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
- NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO |
+ NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO | NETIF_F_GRO_HW |
NETIF_F_RXHASH | NETIF_F_HW_VLAN_CTAG_TX;
if (!chip_is_e1x) {
dev->hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM |
@@ -13309,6 +13309,8 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
dev->features |= dev->hw_features | NETIF_F_HW_VLAN_CTAG_RX;
dev->features |= NETIF_F_HIGHDMA;
+ if (dev->features & NETIF_F_GRO_HW)
+ dev->features &= ~NETIF_F_LRO;
/* Add Loopback capability to the device */
dev->hw_features |= NETIF_F_LOOPBACK;
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next v4 5/5] qede: Use NETIF_F_GRO_HW.
From: Michael Chan @ 2017-12-11 11:41 UTC (permalink / raw)
To: davem; +Cc: netdev, andrew.gospodarek, Ariel Elior, everest-linux-l2
In-Reply-To: <1512992470-28861-1-git-send-email-michael.chan@broadcom.com>
Advertise NETIF_F_GRO_HW and set edev->gro_disable according to the
feature flag. Add qede_fix_features() to drop NETIF_F_GRO_HW if
XDP is running or MTU does not support GRO_HW or GRO is not set.
qede_change_mtu() also checks and disables GRO_HW if MTU is not
supported.
Cc: Ariel Elior <Ariel.Elior@cavium.com>
Cc: everest-linux-l2@cavium.com
Acked-by: Manish Chopra <manish.chopra@cavium.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
drivers/net/ethernet/qlogic/qede/qede.h | 2 ++
drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 3 +++
drivers/net/ethernet/qlogic/qede/qede_filter.c | 21 ++++++++++++++-------
drivers/net/ethernet/qlogic/qede/qede_main.c | 17 ++++++-----------
4 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h
index a3a70ad..8a33651 100644
--- a/drivers/net/ethernet/qlogic/qede/qede.h
+++ b/drivers/net/ethernet/qlogic/qede/qede.h
@@ -494,6 +494,8 @@ int qede_free_tx_pkt(struct qede_dev *edev,
void qede_vlan_mark_nonconfigured(struct qede_dev *edev);
int qede_configure_vlan_filters(struct qede_dev *edev);
+netdev_features_t qede_fix_features(struct net_device *dev,
+ netdev_features_t features);
int qede_set_features(struct net_device *dev, netdev_features_t features);
void qede_set_rx_mode(struct net_device *ndev);
void qede_config_rx_mode(struct net_device *ndev);
diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
index dae7412..4ca3847 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
@@ -940,6 +940,9 @@ int qede_change_mtu(struct net_device *ndev, int new_mtu)
DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
"Configuring MTU size of %d\n", new_mtu);
+ if (new_mtu > PAGE_SIZE)
+ ndev->features &= ~NETIF_F_GRO_HW;
+
/* Set the mtu field and re-start the interface if needed */
args.u.mtu = new_mtu;
args.func = &qede_update_mtu;
diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c
index c1a0708..77aa826 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_filter.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c
@@ -895,19 +895,26 @@ static void qede_set_features_reload(struct qede_dev *edev,
edev->ndev->features = args->u.features;
}
+netdev_features_t qede_fix_features(struct net_device *dev,
+ netdev_features_t features)
+{
+ struct qede_dev *edev = netdev_priv(dev);
+
+ if (edev->xdp_prog || edev->ndev->mtu > PAGE_SIZE ||
+ !(features & NETIF_F_GRO))
+ features &= ~NETIF_F_GRO_HW;
+
+ return features;
+}
+
int qede_set_features(struct net_device *dev, netdev_features_t features)
{
struct qede_dev *edev = netdev_priv(dev);
netdev_features_t changes = features ^ dev->features;
bool need_reload = false;
- /* No action needed if hardware GRO is disabled during driver load */
- if (changes & NETIF_F_GRO) {
- if (dev->features & NETIF_F_GRO)
- need_reload = !edev->gro_disable;
- else
- need_reload = edev->gro_disable;
- }
+ if (changes & NETIF_F_GRO_HW)
+ need_reload = true;
if (need_reload) {
struct qede_reload_args args;
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index 57332b3..90d79ae 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -545,6 +545,7 @@ static int qede_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
#endif
.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
+ .ndo_fix_features = qede_fix_features,
.ndo_set_features = qede_set_features,
.ndo_get_stats64 = qede_get_stats64,
#ifdef CONFIG_QED_SRIOV
@@ -572,6 +573,7 @@ static int qede_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
.ndo_change_mtu = qede_change_mtu,
.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
+ .ndo_fix_features = qede_fix_features,
.ndo_set_features = qede_set_features,
.ndo_get_stats64 = qede_get_stats64,
.ndo_udp_tunnel_add = qede_udp_tunnel_add,
@@ -589,6 +591,7 @@ static int qede_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
.ndo_change_mtu = qede_change_mtu,
.ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
+ .ndo_fix_features = qede_fix_features,
.ndo_set_features = qede_set_features,
.ndo_get_stats64 = qede_get_stats64,
.ndo_udp_tunnel_add = qede_udp_tunnel_add,
@@ -676,7 +679,7 @@ static void qede_init_ndev(struct qede_dev *edev)
ndev->priv_flags |= IFF_UNICAST_FLT;
/* user-changeble features */
- hw_features = NETIF_F_GRO | NETIF_F_SG |
+ hw_features = NETIF_F_GRO | NETIF_F_GRO_HW | NETIF_F_SG |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO6;
@@ -1228,18 +1231,9 @@ static int qede_alloc_sge_mem(struct qede_dev *edev, struct qede_rx_queue *rxq)
dma_addr_t mapping;
int i;
- /* Don't perform FW aggregations in case of XDP */
- if (edev->xdp_prog)
- edev->gro_disable = 1;
-
if (edev->gro_disable)
return 0;
- if (edev->ndev->mtu > PAGE_SIZE) {
- edev->gro_disable = 1;
- return 0;
- }
-
for (i = 0; i < ETH_TPA_MAX_AGGS_NUM; i++) {
struct qede_agg_info *tpa_info = &rxq->tpa_info[i];
struct sw_rx_data *replace_buf = &tpa_info->buffer;
@@ -1269,6 +1263,7 @@ static int qede_alloc_sge_mem(struct qede_dev *edev, struct qede_rx_queue *rxq)
err:
qede_free_sge_mem(edev, rxq);
edev->gro_disable = 1;
+ edev->ndev->features &= ~NETIF_F_GRO_HW;
return -ENOMEM;
}
@@ -1511,7 +1506,7 @@ static void qede_init_fp(struct qede_dev *edev)
edev->ndev->name, queue_id);
}
- edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO);
+ edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW);
}
static int qede_set_real_num_queues(struct qede_dev *edev)
--
1.8.3.1
^ permalink raw reply related
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