* Re: [RFC net-next v2 3/5] net: phy: add private data to mdio_device
From: Andrew Lunn @ 2019-08-28 18:06 UTC (permalink / raw)
To: Ong Boon Leong
Cc: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, netdev,
linux-kernel, peppe.cavallaro, alexandre.torgue, weifeng.voon
In-Reply-To: <20190828174722.6726-4-boon.leong.ong@intel.com>
On Thu, Aug 29, 2019 at 01:47:20AM +0800, Ong Boon Leong wrote:
> PHY converter device is represented as mdio_device and requires private
> data. So, we add pointer for private data to mdio_device struct.
Hi Ong
This was discussed recently with regard to the xilinx_gmii2rgmii.c
driver. You can use the usual dev_get_drvdata() to get private data
associated to the device. I did suggest adding wrappers, so you can
pass a phydev, or and mdiodev.
Andrew
^ permalink raw reply
* Re: [PATCH v2] riscv: add support for SECCOMP and SECCOMP_FILTER
From: Kees Cook @ 2019-08-28 18:01 UTC (permalink / raw)
To: Andy Lutomirski
Cc: David Abdurachmanov, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Oleg Nesterov, Will Drewry, Shuah Khan, Alexei Starovoitov,
Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song,
David Abdurachmanov, Thomas Gleixner, Allison Randal,
Alexios Zavras, Anup Patel, Vincent Chen, Alan Kao, linux-riscv,
linux-kernel, linux-kselftest, netdev, bpf, me
In-Reply-To: <419CB0D1-E51C-49D5-9745-7771C863462F@amacapital.net>
On Wed, Aug 28, 2019 at 10:52:05AM -0700, Andy Lutomirski wrote:
>
>
> > On Aug 25, 2019, at 2:59 PM, Kees Cook <keescook@chromium.org> wrote:
> >
> >> On Thu, Aug 22, 2019 at 01:55:22PM -0700, David Abdurachmanov wrote:
> >> This patch was extensively tested on Fedora/RISCV (applied by default on
> >> top of 5.2-rc7 kernel for <2 months). The patch was also tested with 5.3-rc
> >> on QEMU and SiFive Unleashed board.
> >
> > Oops, I see the mention of QEMU here. Where's the best place to find
> > instructions on creating a qemu riscv image/environment?
>
> I don’t suppose one of you riscv folks would like to contribute riscv support to virtme? virtme-run —arch=riscv would be quite nice, and the total patch should be just a couple lines. Unfortunately, it helps a lot to understand the subtleties of booting the architecture to write those couple lines :)
As it turns out, this is where I'm stuck. All the instructions I can
find are about booting a kernel off a disk image. :(
--
Kees Cook
^ permalink raw reply
* Re: [PATCH v2] riscv: add support for SECCOMP and SECCOMP_FILTER
From: Andy Lutomirski @ 2019-08-28 17:52 UTC (permalink / raw)
To: Kees Cook
Cc: David Abdurachmanov, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Oleg Nesterov, Will Drewry, Shuah Khan, Alexei Starovoitov,
Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song,
David Abdurachmanov, Thomas Gleixner, Allison Randal,
Alexios Zavras, Anup Patel, Vincent Chen, Alan Kao, linux-riscv,
linux-kernel, linux-kselftest, netdev, bpf, me
In-Reply-To: <201908251451.73C6812E8@keescook>
> On Aug 25, 2019, at 2:59 PM, Kees Cook <keescook@chromium.org> wrote:
>
>> On Thu, Aug 22, 2019 at 01:55:22PM -0700, David Abdurachmanov wrote:
>> This patch was extensively tested on Fedora/RISCV (applied by default on
>> top of 5.2-rc7 kernel for <2 months). The patch was also tested with 5.3-rc
>> on QEMU and SiFive Unleashed board.
>
> Oops, I see the mention of QEMU here. Where's the best place to find
> instructions on creating a qemu riscv image/environment?
I don’t suppose one of you riscv folks would like to contribute riscv support to virtme? virtme-run —arch=riscv would be quite nice, and the total patch should be just a couple lines. Unfortunately, it helps a lot to understand the subtleties of booting the architecture to write those couple lines :)
^ permalink raw reply
* [RFC net-next v2 5/5] net: stmmac: add dwxpcs boardinfo for mdio_device registration
From: Ong Boon Leong @ 2019-08-28 17:47 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828174722.6726-1-boon.leong.ong@intel.com>
For EHL & TGL Ethernet PCS, the mdio bus address is the same across all
TSN controller instances. External PHY is using default mdio bus address of
0x0. As Ethernet DW PCS is only applicable for SGMII interface, we only
register setup_intel_mgbe_phy_conv() for all TSN controller with SGMII
interface only.
Also introduce callback for remove mdio_device for unloading driver.
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 +
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 25 +++++++++++
.../net/ethernet/stmicro/stmmac/stmmac_pci.c | 45 ++++++++++++++++++-
include/linux/stmmac.h | 3 ++
5 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 2325b40dff6e..db4332863611 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -200,6 +200,7 @@ endif
config STMMAC_PCI
tristate "STMMAC PCI bus support"
depends on STMMAC_ETH && PCI
+ select DWXPCS
---help---
This selects the platform specific bus support for the stmmac driver.
This driver was tested on XLINX XC2V3000 FF1152AMT0221
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index dcb2e29a5717..d4e232223941 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -29,6 +29,7 @@ struct stmmac_resources {
int wol_irq;
int lpi_irq;
int irq;
+ int phy_conv_irq;
};
struct stmmac_tx_info {
@@ -203,6 +204,7 @@ struct stmmac_priv {
void __iomem *mmcaddr;
void __iomem *ptpaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ int phy_conv_irq;
#ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_dir;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 06ccd216ae90..43e3d3799581 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2726,11 +2726,23 @@ static int stmmac_open(struct net_device *dev)
}
}
+ /* Start phy converter after MDIO bus IRQ handling is up */
+ if (priv->plat->setup_phy_conv) {
+ ret = priv->plat->setup_phy_conv(priv->mii, priv->phy_conv_irq);
+ if (ret < 0) {
+ netdev_err(priv->dev,
+ "%s: ERROR: setup phy conv (error: %d)\n",
+ __func__, ret);
+ goto phy_conv_error;
+ }
+ }
+
stmmac_enable_all_queues(priv);
stmmac_start_all_queues(priv);
return 0;
+phy_conv_error:
lpiirq_error:
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
@@ -2760,6 +2772,7 @@ static int stmmac_release(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
u32 chan;
+ int ret;
if (priv->eee_enabled)
del_timer_sync(&priv->eee_ctrl_timer);
@@ -2782,6 +2795,17 @@ static int stmmac_release(struct net_device *dev)
if (priv->lpi_irq > 0)
free_irq(priv->lpi_irq, dev);
+ /* Start phy converter after MDIO bus IRQ handling is up */
+ if (priv->plat->remove_phy_conv) {
+ ret = priv->plat->remove_phy_conv(priv->mii);
+ if (ret < 0) {
+ netdev_err(priv->dev,
+ "%s: ERROR: remove phy conv (error: %d)\n",
+ __func__, ret);
+ return 0;
+ }
+ }
+
/* Stop TX/RX DMA and clear the descriptors */
stmmac_stop_all_dma(priv);
@@ -4424,6 +4448,7 @@ int stmmac_dvr_probe(struct device *device,
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
priv->lpi_irq = res->lpi_irq;
+ priv->phy_conv_irq = res->phy_conv_irq;
if (!IS_ERR_OR_NULL(res->mac))
memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 20906287b6d4..c3dfb0e9b025 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -10,9 +10,10 @@
*******************************************************************************/
#include <linux/clk-provider.h>
+#include <linux/phy.h>
#include <linux/pci.h>
#include <linux/dmi.h>
-
+#include <linux/dwxpcs.h>
#include "stmmac.h"
/*
@@ -109,6 +110,42 @@ static const struct stmmac_pci_info stmmac_pci_info = {
.setup = stmmac_default_data,
};
+static struct dwxpcs_platform_data intel_mgbe_pdata = {
+ .mode = DWXPCS_MODE_SGMII_AN,
+ .ext_phy_addr = 0x0,
+};
+
+static struct mdio_board_info intel_mgbe_bdinfo = {
+ .bus_id = "stmmac-1",
+ .modalias = "dwxpcs",
+ .mdio_addr = 0x16,
+ .platform_data = &intel_mgbe_pdata,
+};
+
+static int setup_intel_mgbe_phy_conv(struct mii_bus *bus, int irq)
+{
+ struct dwxpcs_platform_data *pdata = &intel_mgbe_pdata;
+
+ pdata->irq = irq;
+
+ return mdiobus_create_device(bus, &intel_mgbe_bdinfo);
+}
+
+static int remove_intel_mgbe_phy_conv(struct mii_bus *bus)
+{
+ struct mdio_board_info *bdinfo = &intel_mgbe_bdinfo;
+ struct mdio_device *mdiodev;
+
+ mdiodev = mdiobus_get_mdio_device(bus, bdinfo->mdio_addr);
+
+ if (!mdiodev)
+ return -1;
+
+ mdio_device_remove(mdiodev);
+
+ return 0;
+}
+
static int intel_mgbe_common_data(struct pci_dev *pdev,
struct plat_stmmacenet_data *plat)
{
@@ -197,6 +234,11 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
/* Set the maxmtu to a default of JUMBO_LEN */
plat->maxmtu = JUMBO_LEN;
+ if (plat->interface == PHY_INTERFACE_MODE_SGMII) {
+ plat->setup_phy_conv = setup_intel_mgbe_phy_conv;
+ plat->remove_phy_conv = remove_intel_mgbe_phy_conv;
+ }
+
return 0;
}
@@ -441,6 +483,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
res.addr = pcim_iomap_table(pdev)[i];
res.wol_irq = pdev->irq;
res.irq = pdev->irq;
+ res.phy_conv_irq = res.irq;
return stmmac_dvr_probe(&pdev->dev, plat, &res);
}
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 7ad7ae35cf88..9ffd0e9c21b1 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -12,6 +12,7 @@
#ifndef __STMMAC_PLATFORM_DATA
#define __STMMAC_PLATFORM_DATA
+#include <linux/phy.h>
#include <linux/platform_device.h>
#define MTL_MAX_RX_QUEUES 8
@@ -162,6 +163,8 @@ struct plat_stmmacenet_data {
int (*init)(struct platform_device *pdev, void *priv);
void (*exit)(struct platform_device *pdev, void *priv);
struct mac_device_info *(*setup)(void *priv);
+ int (*setup_phy_conv)(struct mii_bus *bus, int irq);
+ int (*remove_phy_conv)(struct mii_bus *bus);
void *bsp_priv;
struct clk *stmmac_clk;
struct clk *pclk;
--
2.17.0
^ permalink raw reply related
* [RFC net-next v2 3/5] net: phy: add private data to mdio_device
From: Ong Boon Leong @ 2019-08-28 17:47 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828174722.6726-1-boon.leong.ong@intel.com>
PHY converter device is represented as mdio_device and requires private
data. So, we add pointer for private data to mdio_device struct.
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
include/linux/mdio.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index e0ccd56a7ac0..fc7dfbe75006 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -40,6 +40,8 @@ struct mdio_device {
struct reset_control *reset_ctrl;
unsigned int reset_assert_delay;
unsigned int reset_deassert_delay;
+ /* Private data */
+ void *priv;
};
#define to_mdio_device(d) container_of(d, struct mdio_device, dev)
--
2.17.0
^ permalink raw reply related
* [RFC net-next v2 2/5] net: phy: introduce mdiobus_get_mdio_device
From: Ong Boon Leong @ 2019-08-28 17:47 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828174722.6726-1-boon.leong.ong@intel.com>
Add the function to get mdio_device based on the mdio addr.
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
drivers/net/phy/mdio_bus.c | 6 ++++++
include/linux/mdio.h | 1 +
2 files changed, 7 insertions(+)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 06658d9197a1..96ef94f87ff1 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -130,6 +130,12 @@ struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
}
EXPORT_SYMBOL(mdiobus_get_phy);
+struct mdio_device *mdiobus_get_mdio_device(struct mii_bus *bus, int addr)
+{
+ return bus->mdio_map[addr];
+}
+EXPORT_SYMBOL(mdiobus_get_mdio_device);
+
bool mdiobus_is_registered_device(struct mii_bus *bus, int addr)
{
return bus->mdio_map[addr];
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index e8242ad88c81..e0ccd56a7ac0 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -315,6 +315,7 @@ int mdiobus_register_device(struct mdio_device *mdiodev);
int mdiobus_unregister_device(struct mdio_device *mdiodev);
bool mdiobus_is_registered_device(struct mii_bus *bus, int addr);
struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr);
+struct mdio_device *mdiobus_get_mdio_device(struct mii_bus *bus, int addr);
/**
* mdio_module_driver() - Helper macro for registering mdio drivers
--
2.17.0
^ permalink raw reply related
* [RFC net-next v2 4/5] net: phy: introducing support for DWC xPCS logics for EHL & TGL
From: Ong Boon Leong @ 2019-08-28 17:47 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828174722.6726-1-boon.leong.ong@intel.com>
xPCS is DWC Ethernet Physical Coding Sublayer that can be integrated with
Ethernet MAC controller and acts as converter between GMII and SGMII. An
example is as shown below whereby DWC xPCS is integrated with DW EQoS MAC
to form GbE Controller.
<-----------------GbE Controller---------->|<--External PHY chip-->
+----------+ +----+ +---+ +--------------+
| EQoS | <-GMII->| DW |<-->|PHY| <-- SGMII --> | External GbE |
| MAC | |xPCS| |IF | | PHY Chip |
+----------+ +----+ +---+ +--------------+
^ ^ ^
| | |
+---------------------MDIO-------------------------+
xPCS is a Clause-45 MDIO Manageable Device (MMD) and supports basic
functionalities for initializing xPCS and configuring auto negotiation(AN),
loopback, link status, AN advertisement and Link Partner ability are
implemented. The implementation supports the C37 AN for 1000BASE-X and
SGMII (MAC side SGMII only).
Tested-by: Tan, Tee Min <tee.min.tan@intel.com>
Reviewed-by: Voon Weifeng <weifeng.voon@intel.com>
Reviewed-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
drivers/net/phy/Kconfig | 9 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/dwxpcs.c | 417 +++++++++++++++++++++++++++++++++++++++
include/linux/dwxpcs.h | 16 ++
4 files changed, 443 insertions(+)
create mode 100644 drivers/net/phy/dwxpcs.c
create mode 100644 include/linux/dwxpcs.h
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 03be30cde552..fd037f5366d8 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -364,6 +364,15 @@ config DP83867_PHY
---help---
Currently supports the DP83867 PHY.
+config DWXPCS
+ tristate "Synopsys DesignWare PCS converter driver"
+ help
+ This driver supports DW PCS IP that provides the Serial Gigabit
+ Media Independent Interface(SGMII) between Ethernet physical media
+ devices and the Gigabit Ethernet controller.
+
+ Currently tested with stmmac.
+
config FIXED_PHY
tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index a03437e091f3..5def985ae3ca 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_DP83822_PHY) += dp83822.o
obj-$(CONFIG_DP83TC811_PHY) += dp83tc811.o
obj-$(CONFIG_DP83848_PHY) += dp83848.o
obj-$(CONFIG_DP83867_PHY) += dp83867.o
+obj-$(CONFIG_DWXPCS) += dwxpcs.o
obj-$(CONFIG_FIXED_PHY) += fixed_phy.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o
diff --git a/drivers/net/phy/dwxpcs.c b/drivers/net/phy/dwxpcs.c
new file mode 100644
index 000000000000..f0003cec6871
--- /dev/null
+++ b/drivers/net/phy/dwxpcs.c
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Intel Corporation.
+ * DWC Ethernet Physical Coding Sublayer for GMII2SGMII Converter
+ */
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/dwxpcs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+
+/* XPCS MII MMD Device Addresses */
+#define XPCS_MDIO_MII_MMD MDIO_MMD_VEND2
+
+/* MII MMD registers offsets */
+#define MDIO_MII_MMD_DIGITAL_CTRL_1 0x8000 /* Digital Control 1 */
+#define MDIO_MII_MMD_AN_CTRL 0x8001 /* AN Control */
+#define MDIO_MII_MMD_AN_STAT 0x8002 /* AN Status */
+
+/* MII MMD SR AN Advertisement & Link Partner Ability are slightly
+ * different from MII_ADVERTISEMENT & MII_LPA in below fields:
+ */
+#define MDIO_MII_MMD_HD BIT(6) /* Half duplex */
+#define MDIO_MII_MMD_FD BIT(5) /* Full duplex */
+#define MDIO_MII_MMD_PSE_SHIFT 7 /* Pause Ability shift */
+#define MDIO_MII_MMD_PSE GENMASK(8, 7) /* Pause Ability */
+#define MDIO_MII_MMD_PSE_NO 0x0
+#define MDIO_MII_MMD_PSE_ASYM 0x1
+#define MDIO_MII_MMD_PSE_SYM 0x2
+#define MDIO_MII_MMD_PSE_BOTH 0x3
+
+/* Automatic Speed Mode Change for MAC side SGMII AN */
+#define MDIO_MII_MMD_DIGI_CTRL_1_MAC_AUTO_SW BIT(9)
+
+/* MII MMD AN Control defines */
+#define MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT 3 /* TX Config shift */
+#define AN_CTRL_TX_CONF_PHY_SIDE_SGMII 0x1 /* PHY side SGMII mode */
+#define AN_CTRL_TX_CONF_MAC_SIDE_SGMII 0x0 /* MAC side SGMII mode */
+#define MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT 1 /* PCS Mode shift */
+#define MDIO_MII_MMD_AN_CTRL_PCS_MD GENMASK(2, 1) /* PCS Mode */
+#define AN_CTRL_PCS_MD_C37_1000BASEX 0x0 /* C37 AN for 1000BASE-X */
+#define AN_CTRL_PCS_MD_C37_SGMII 0x2 /* C37 AN for SGMII */
+#define MDIO_MII_MMD_AN_CTRL_AN_INTR_EN BIT(0) /* AN Complete Intr Enable */
+
+/* MII MMD AN Status defines for SGMII AN Status */
+#define AN_STAT_C37_AN_CMPLT BIT(0) /* AN Complete Intr */
+#define AN_STAT_SGMII_AN_FD BIT(1) /* Full Duplex */
+#define AN_STAT_SGMII_AN_SPEED_SHIFT 2 /* AN Speed shift */
+#define AN_STAT_SGMII_AN_SPEED GENMASK(3, 2) /* AN Speed */
+#define AN_STAT_SGMII_AN_10MBPS 0x0 /* 10 Mbps */
+#define AN_STAT_SGMII_AN_100MBPS 0x1 /* 100 Mbps */
+#define AN_STAT_SGMII_AN_1000MBPS 0x2 /* 1000 Mbps */
+#define AN_STAT_SGMII_AN_LNKSTS BIT(4) /* Link Status */
+
+enum dwxpcs_state_t {
+ __DWXPCS_REMOVING,
+ __DWXPCS_TASK_SCHED,
+};
+
+struct pcs_stats {
+ int link;
+ int speed;
+ int duplex;
+};
+
+struct dwxpcs_priv {
+ struct phy_device *phy_dev;
+ struct phy_driver *phy_drv;
+ struct phy_device cached_phy_dev;
+ struct phy_driver conv_phy_drv;
+ struct mdio_device *mdiodev;
+ struct pcs_stats stats;
+ struct dwxpcs_platform_data *pdata;
+ char int_name[IFNAMSIZ];
+ unsigned long state;
+ struct workqueue_struct *int_wq;
+ struct work_struct an_task;
+};
+
+/* DW xPCS mdiobus_read and mdiobus_write helper functions */
+#define xpcs_read(dev, reg) \
+ mdiobus_read(bus, xpcs_addr, \
+ MII_ADDR_C45 | (reg) | \
+ ((dev) << MII_DEVADDR_C45_SHIFT))
+#define xpcs_write(dev, reg, val) \
+ mdiobus_write(bus, xpcs_addr, \
+ MII_ADDR_C45 | (reg) | \
+ ((dev) << MII_DEVADDR_C45_SHIFT), val)
+
+static void dwxpcs_init(struct dwxpcs_priv *priv)
+{
+ struct mii_bus *bus = priv->mdiodev->bus;
+ int xpcs_addr = priv->mdiodev->addr;
+ int pcs_mode = priv->pdata->mode;
+ int phydata;
+
+ if (pcs_mode == DWXPCS_MODE_SGMII_AN) {
+ /* For AN for SGMII mode, the settings are :-
+ * 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
+ * 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
+ * DW xPCS used with DW EQoS MAC is always MAC
+ * side SGMII.
+ * 3) VR_MII_AN_CTRL Bit(0) [AN_INTR_EN] = 1b (AN Interrupt
+ * enabled)
+ * 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
+ * speed/duplex mode change by HW after SGMII AN complete)
+ * Note: Since it is MAC side SGMII, there is no need to set
+ * SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config
+ * from PHY about the link state change after C28 AN
+ * is completed between PHY and Link Partner.
+ */
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_CTRL);
+ phydata &= ~MDIO_MII_MMD_AN_CTRL_PCS_MD;
+
+ phydata |= MDIO_MII_MMD_AN_CTRL_AN_INTR_EN |
+ (AN_CTRL_PCS_MD_C37_SGMII <<
+ MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT &
+ MDIO_MII_MMD_AN_CTRL_PCS_MD) |
+ (AN_CTRL_TX_CONF_MAC_SIDE_SGMII <<
+ MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT);
+ xpcs_write(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_CTRL, phydata);
+
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD,
+ MDIO_MII_MMD_DIGITAL_CTRL_1);
+ phydata |= MDIO_MII_MMD_DIGI_CTRL_1_MAC_AUTO_SW;
+ xpcs_write(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_DIGITAL_CTRL_1,
+ phydata);
+ } else {
+ /* For AN for 1000BASE-X mode, the settings are :-
+ * 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 00b (1000BASE-X C37)
+ * 2) VR_MII_AN_CTRL Bit(0) [AN_INTR_EN] = 1b (AN Interrupt
+ * enabled)
+ * 3) SR_MII_AN_ADV Bit(6)[FD] = 1b (Full Duplex)
+ * Note: Half Duplex is rarely used, so don't advertise.
+ * 4) SR_MII_AN_ADV Bit(8:7)[PSE] = 11b (Sym & Asym Pause)
+ */
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_CTRL);
+ phydata &= ~MDIO_MII_MMD_AN_CTRL_PCS_MD;
+ phydata |= MDIO_MII_MMD_AN_CTRL_AN_INTR_EN |
+ (AN_CTRL_PCS_MD_C37_1000BASEX <<
+ MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT &
+ MDIO_MII_MMD_AN_CTRL_PCS_MD);
+ xpcs_write(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_CTRL, phydata);
+
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD, MII_ADVERTISE);
+ phydata |= MDIO_MII_MMD_FD |
+ (MDIO_MII_MMD_PSE_BOTH << MDIO_MII_MMD_PSE_SHIFT);
+ xpcs_write(XPCS_MDIO_MII_MMD, MII_ADVERTISE, phydata);
+ }
+}
+
+static int dwxpcs_read_status(struct phy_device *phydev)
+{
+ struct dwxpcs_priv *priv = (struct dwxpcs_priv *)phydev->priv;
+ struct mii_bus *bus = priv->mdiodev->bus;
+ int xpcs_addr = priv->mdiodev->addr;
+ int pcs_mode = priv->pdata->mode;
+ int phydata;
+ int err;
+
+ if (priv->phy_drv->read_status)
+ err = priv->phy_drv->read_status(phydev);
+ else
+ err = genphy_read_status(phydev);
+
+ if (err < 0)
+ return err;
+
+ /* For SGMII AN, we are done as the speed/duplex are automatically
+ * set because we have initialized 'MAC_AUTO_SW' for MAC side SGMII.
+ */
+ if (pcs_mode == DWXPCS_MODE_1000BASEX_AN) {
+ /* For 1000BASE-X AN, we need to adjust duplex mode according
+ * to link partner. No need to update speed as it is always
+ * 1000Mbps.
+ */
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD, MII_BMCR);
+ phydata &= ~BMCR_FULLDPLX;
+ phydata |= phydev->duplex ? BMCR_FULLDPLX : 0;
+ xpcs_write(XPCS_MDIO_MII_MMD, MII_BMCR, phydata);
+ }
+
+ return 0;
+}
+
+static void dwxpcs_get_linkstatus(struct dwxpcs_priv *priv, int an_stat)
+{
+ struct mii_bus *bus = priv->mdiodev->bus;
+ struct pcs_stats *stats = &priv->stats;
+ int xpcs_addr = priv->mdiodev->addr;
+ int pcs_mode = priv->pdata->mode;
+
+ if (pcs_mode == DWXPCS_MODE_SGMII_AN) {
+ /* Check the SGMII AN link status */
+ if (an_stat & AN_STAT_SGMII_AN_LNKSTS) {
+ int speed_value;
+
+ stats->link = 1;
+
+ speed_value = ((an_stat & AN_STAT_SGMII_AN_SPEED) >>
+ AN_STAT_SGMII_AN_SPEED_SHIFT);
+ if (speed_value == AN_STAT_SGMII_AN_1000MBPS)
+ stats->speed = SPEED_1000;
+ else if (speed_value == AN_STAT_SGMII_AN_100MBPS)
+ stats->speed = SPEED_100;
+ else
+ stats->speed = SPEED_10;
+
+ if (an_stat & AN_STAT_SGMII_AN_FD)
+ stats->duplex = 1;
+ else
+ stats->duplex = 0;
+ } else {
+ stats->link = 0;
+ }
+ } else if (pcs_mode == DWXPCS_MODE_1000BASEX_AN) {
+ /* For 1000BASE-X AN, 1000BASE-X is always 1000Mbps.
+ * For duplex mode, we read from BMCR_FULLDPLX which is
+ * only valid if BMCR_ANENABLE is not enabeld.
+ */
+ int phydata = xpcs_read(XPCS_MDIO_MII_MMD, MII_BMCR);
+
+ stats->link = 1;
+ stats->speed = SPEED_1000;
+ if (!(phydata & BMCR_ANENABLE))
+ stats->duplex = phydata & BMCR_FULLDPLX ? 1 : 0;
+ }
+}
+
+static void dwxpcs_irq_handle(struct dwxpcs_priv *priv)
+{
+ struct mii_bus *bus = priv->mdiodev->bus;
+ struct device *dev = &priv->mdiodev->dev;
+ int xpcs_addr = priv->mdiodev->addr;
+ int an_stat;
+
+ /* AN status */
+ an_stat = xpcs_read(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_STAT);
+
+ if (an_stat & AN_STAT_C37_AN_CMPLT) {
+ struct pcs_stats *stats = &priv->stats;
+
+ dwxpcs_get_linkstatus(priv, an_stat);
+
+ /* Clear C37 AN complete status by writing zero */
+ xpcs_write(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_STAT, 0);
+
+ dev_info(dev, "%s: Link = %d - %d/%s\n",
+ __func__,
+ stats->link,
+ stats->speed,
+ stats->duplex ? "Full" : "Half");
+ }
+}
+
+static void dwxpcs_an_task(struct work_struct *work)
+{
+ struct dwxpcs_priv *priv = container_of(work,
+ struct dwxpcs_priv,
+ an_task);
+ dwxpcs_irq_handle(priv);
+
+ clear_bit(__DWXPCS_TASK_SCHED, &priv->state);
+}
+
+static irqreturn_t dwxpcs_interrupt(int irq, void *dev_id)
+{
+ struct dwxpcs_priv *priv = (struct dwxpcs_priv *)dev_id;
+
+ /* Handle the clearing of AN status outside of interrupt context
+ * as it involves mdiobus_read() & mdiobus_write().
+ */
+ if (!test_bit(__DWXPCS_REMOVING, &priv->state) &&
+ !test_and_set_bit(__DWXPCS_TASK_SCHED, &priv->state)) {
+ queue_work(priv->int_wq, &priv->an_task);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id dwxpcs_acpi_match[] = {
+ { "INTC1033" }, /* EHL Ethernet PCS */
+ { "INTC1034" }, /* TGL Ethernet PCS */
+ { },
+};
+
+MODULE_DEVICE_TABLE(acpi, dwxpcs_acpi_match);
+#endif // CONFIG_ACPI
+
+static int dwxpcs_probe(struct mdio_device *mdiodev)
+{
+ struct device_node *phy_node;
+ struct dwxpcs_priv *priv;
+ struct device_node *np;
+ struct device *dev;
+ int ret;
+
+ dev = &mdiodev->dev;
+ np = dev->of_node;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (np) {
+ /* Handle mdio_device registered through devicetree */
+ phy_node = of_parse_phandle(np, "phy-handle", 0);
+ if (!phy_node) {
+ dev_err(dev, "Couldn't parse phy-handle\n");
+ return -ENODEV;
+ }
+
+ priv->phy_dev = of_phy_find_device(phy_node);
+ of_node_put(phy_node);
+ if (!priv->phy_dev) {
+ dev_info(dev, "Couldn't find phydev\n");
+ return -EPROBE_DEFER;
+ }
+ } else {
+ /* Handle mdio_device registered through mdio_board_info */
+ priv->pdata = (struct dwxpcs_platform_data *)dev->platform_data;
+
+ priv->phy_dev = mdiobus_get_phy(mdiodev->bus,
+ priv->pdata->ext_phy_addr);
+ }
+
+ if (!priv->phy_dev) {
+ dev_info(dev, "Couldn't find phydev\n");
+ return -EPROBE_DEFER;
+ }
+
+ if (!priv->phy_dev->drv) {
+ dev_info(dev, "Attached phy not ready\n");
+ return -EPROBE_DEFER;
+ }
+
+ priv->mdiodev = mdiodev;
+
+ /* Initialize DW XPCS */
+ dwxpcs_init(priv);
+
+ priv->phy_drv = priv->phy_dev->drv;
+ memcpy(&priv->conv_phy_drv, priv->phy_dev->drv,
+ sizeof(struct phy_driver));
+ priv->conv_phy_drv.read_status = dwxpcs_read_status;
+ /* Store a copy of phy_dev info for remove() later */
+ priv->cached_phy_dev.priv = priv->phy_dev->priv;
+ priv->cached_phy_dev.drv = priv->phy_dev->drv;
+ priv->phy_dev->priv = priv;
+ priv->phy_dev->drv = &priv->conv_phy_drv;
+
+ if (priv->pdata->irq > 0) {
+ char *int_name;
+
+ INIT_WORK(&priv->an_task, dwxpcs_an_task);
+ clear_bit(__DWXPCS_TASK_SCHED, &priv->state);
+
+ int_name = priv->int_name;
+ sprintf(int_name, "%s-%d", "dwxpcs", priv->mdiodev->dev.id);
+ priv->int_wq = create_singlethread_workqueue(int_name);
+ if (!priv->int_wq) {
+ dev_err(dev, "%s: Failed to create workqueue\n",
+ int_name);
+ return -ENOMEM;
+ }
+
+ ret = request_irq(priv->pdata->irq, dwxpcs_interrupt,
+ IRQF_SHARED, int_name, priv);
+ if (unlikely(ret < 0)) {
+ destroy_workqueue(priv->int_wq);
+ dev_err(dev, "%s: Allocating DW XPCS IRQ %d (%d)\n",
+ __func__, priv->pdata->irq, ret);
+ return ret;
+ }
+ }
+ dev_info(dev, "%s: DW XPCS mdio device (IRQ: %d) probed successful\n",
+ __func__, priv->pdata->irq);
+
+ mdiodev->priv = priv;
+
+ return 0;
+}
+
+static void dwxpcs_remove(struct mdio_device *mdiodev)
+{
+ struct dwxpcs_priv *priv = (struct dwxpcs_priv *)mdiodev->priv;
+
+ set_bit(__DWXPCS_REMOVING, &priv->state);
+
+ /* Restore the original phy_device info */
+ priv->phy_dev->priv = priv->cached_phy_dev.priv;
+ priv->phy_dev->drv = priv->cached_phy_dev.drv;
+
+ free_irq(priv->pdata->irq, priv);
+ if (priv->int_wq)
+ destroy_workqueue(priv->int_wq);
+}
+
+static struct mdio_driver dwxpcs_driver = {
+ .probe = dwxpcs_probe,
+ .remove = dwxpcs_remove,
+ .mdiodrv.driver = {
+ .name = "dwxpcs",
+ .acpi_match_table = ACPI_PTR(dwxpcs_acpi_match),
+ },
+};
+
+mdio_module_driver(dwxpcs_driver);
+
+MODULE_DESCRIPTION("DW xPCS converter driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/dwxpcs.h b/include/linux/dwxpcs.h
new file mode 100644
index 000000000000..2082e800ee04
--- /dev/null
+++ b/include/linux/dwxpcs.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_DWXPCS_H
+#define __LINUX_DWXPCS_H
+
+enum dwxpcs_pcs_mode {
+ DWXPCS_MODE_SGMII_AN,
+ DWXPCS_MODE_1000BASEX_AN,
+};
+
+struct dwxpcs_platform_data {
+ int irq;
+ enum dwxpcs_pcs_mode mode;
+ int ext_phy_addr;
+};
+
+#endif
--
2.17.0
^ permalink raw reply related
* [RFC net-next v2 1/5] net: phy: make mdiobus_create_device() function callable from Eth driver
From: Ong Boon Leong @ 2019-08-28 17:47 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828174722.6726-1-boon.leong.ong@intel.com>
PHY converter and external PHY drivers depend on MDIO functions of Eth
driver and such MDIO read/write completion may fire IRQ. The ISR for MDIO
completion IRQ is done in the open() function of driver.
For PHY converter mdio driver that registers ISR event that uses MDIO
read/write function during its probe() function, the MDIO ISR should have
been performed a head of time before mdio driver probe() is called. It is
for reason as such, the mdio device creation and registration will need
to be callable from Eth driver open() function.
Why existing way to register mdio_device for PHY converter that is done
via mdiobus_register_board_info() is not feasible is the mdio device
creation and registration happens inside Eth driver probe() function,
specifically in mdiobus_setup_mdiodevfrom_board_info() that is called
by mdiobus_register().
Therefore, to fulfill the need mentioned above, we make mdiobus_create_
device() to be callable from Eth driver open().
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
drivers/net/phy/mdio_bus.c | 5 +++--
include/linux/phy.h | 7 +++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index bd04fe762056..06658d9197a1 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -338,8 +338,8 @@ static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,
*
* Returns 0 on success or < 0 on error.
*/
-static int mdiobus_create_device(struct mii_bus *bus,
- struct mdio_board_info *bi)
+int mdiobus_create_device(struct mii_bus *bus,
+ struct mdio_board_info *bi)
{
struct mdio_device *mdiodev;
int ret = 0;
@@ -359,6 +359,7 @@ static int mdiobus_create_device(struct mii_bus *bus,
return ret;
}
+EXPORT_SYMBOL(mdiobus_create_device);
/**
* __mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
diff --git a/include/linux/phy.h b/include/linux/phy.h
index d26779f1fb6b..4524db57fe0b 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1249,12 +1249,19 @@ struct mdio_board_info {
#if IS_ENABLED(CONFIG_MDIO_DEVICE)
int mdiobus_register_board_info(const struct mdio_board_info *info,
unsigned int n);
+int mdiobus_create_device(struct mii_bus *bus, struct mdio_board_info *bi);
#else
static inline int mdiobus_register_board_info(const struct mdio_board_info *i,
unsigned int n)
{
return 0;
}
+
+static inline int mdiobus_create_device(struct mii_bus *bus,
+ struct mdio_board_info *bi)
+{
+ return 0;
+}
#endif
--
2.17.0
^ permalink raw reply related
* [RFC net-next v2 0/5] PHY converter driver for DW xPCS IP
From: Ong Boon Leong @ 2019-08-28 17:47 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
My apology for sending RFC v1 with incorrect email for
peppe.cavallaro@st.com. Please use RFC v2 for discussion. Thanks.
Following review comment from Florian and discussion in below thread:-
https://patchwork.ozlabs.org/patch/1109777/
This RFC is to solicit feedback on the implementation of PHY converter
driver for DW xPCS and some changes in the mdiobus API to prepare for
mdio device registration during driver open() instead of probe() phase
for non-DT platform. The implementation in this Phy Converter has DT
registration for future expansion, however, it is not tested in our
current platform.
The 1st three patches involve changes in existing mdiobus API:-
1) Make mdiobus_create_device() function callable from Ethernet driver
2) Introduce new API mdiobus_get_mdio_device()
3) Add private data for struct mdio_device so that DW xPCS specific
private data can be established between the pairing Ethernet
controller for non-DT way.
The reason for changes for mdiobus_create_device() &
mdiobus_get_mdio_device() is to allow Eth driver to be able to create
mdio device for PHY converter driver when Ethernet driver open() is
called. Existing way for registering mdio device for non-DT appraoch
is through mdiobus_register_board_info() and the mdio device creation
happens inside Ethernet probe() whereby IRQ is not setup. The mdio
device registration happens in mdiobus_register() -->
mdiobus_setup_mdiodevfrom_board_info(), and it becomes an issue for
Phy Converter such as dwxpcs that requires IRQ setup before, i.e.
inside Ethernet controller open().
The 4th patch is for PHY Converter driver for DW xPCS.
Large portion of main logics of this code has been reviewed in the
past in above review thread and all review inputs have been factored.
First, the loading of PHY converter driver is through ACPI Device ID.
The current implementation also has logics for DT style, but since
we don't have such platform, we the DT implementation as place-holder
for anyone that needs in future. The DT implementation follows the
design of drivers/net/phy/xilinx_gmii2rgmii.c closely.
What is extra is setup for DW xPCS IRQ request. In current EHL & TGL
implementation, the IRQ is routed from MAC controller. For non-DT way,
the IRQ line is tied to Ethernet driver (PCI enum), and we need a
way to pass IRQ info from Ethernet driver to PHY converter driver
during the creation of mdio device. Therefore, this is the reason
for the 1st 3 patches. All the ISR does is to kick the workqueue to
process the IRQ as we cannot call mdio_read() and mdio_write() inside
ISR.
The 5th (last) patch shows how the associated PHY converter mdio device
is setup in Ethernet controller open() function and removed during
stop(). The implementation is done in stmmac pci driver.
With this implementation, now, we have dwxpcs implemented as PHY driver
and the hook from stmmac driver for non-DT style is done through
platform-specific data related to EHL & TGL when SGMII interface is
selected. The PHY converter driver will still be beneficial for other
platform that would need it and may use DT to enable the PHY converter
driver and mdio device through DT definition.
Please kindly review this RFC and provide any feedback/concern that
the community may have. Appreciate your time here.
Thanks
Boon Leong
Ong Boon Leong (5):
net: phy: make mdiobus_create_device() function callable from Eth
driver
net: phy: introduce mdiobus_get_mdio_device
net: phy: add private data to mdio_device
net: phy: introducing support for DWC xPCS logics for EHL & TGL
net: stmmac: add dwxpcs boardinfo for mdio_device registration
drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 +
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 25 ++
.../net/ethernet/stmicro/stmmac/stmmac_pci.c | 45 +-
drivers/net/phy/Kconfig | 9 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/dwxpcs.c | 417 ++++++++++++++++++
drivers/net/phy/mdio_bus.c | 11 +-
include/linux/dwxpcs.h | 16 +
include/linux/mdio.h | 3 +
include/linux/phy.h | 7 +
include/linux/stmmac.h | 3 +
12 files changed, 537 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/phy/dwxpcs.c
create mode 100644 include/linux/dwxpcs.h
--
2.17.0
^ permalink raw reply
* [PATCH] igb: add rx drop enable attribute
From: Robert Beckett @ 2019-08-28 17:38 UTC (permalink / raw)
To: intel-wired-lan; +Cc: Robert Beckett, Jeff Kirsher, David S. Miller, netdev
To allow userland to enable or disable dropping packets when descriptor
ring is exhausted, add an adapter rx_drop_en attribute.
This can be used in conjunction with flow control to mitigate packet storms
(e.g. due to network loop or DoS) by forcing the network adapter to send
pause frames whenever the ring is close to exhaustion.
By default this will maintain previous behaviour of enabling dropping of
packets during ring buffer exhaustion.
Some use cases prefer to not drop packets upon exhaustion, but instead
use flow control to limit ingress rates and ensure no dropped packets.
This is useful when the host CPU cannot keep up with packet delivery,
but data delivery is more important than throughput via multiple queues.
Userland can write 0 to rx_drop_en to disable packet dropping via udev.
Signed-off-by: Robert Beckett <bob.beckett@collabora.com>
---
drivers/net/ethernet/intel/igb/igb.h | 1 +
drivers/net/ethernet/intel/igb/igb_main.c | 60 ++++++++++++++++++++++-
2 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index ca54e268d157..efada57a05e1 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -594,6 +594,7 @@ struct igb_adapter {
struct igb_mac_addr *mac_table;
struct vf_mac_filter vf_macs;
struct vf_mac_filter *vf_mac_list;
+ bool rx_drop_enable; /* drop packets when descriptor ring exhausted */
};
/* flags controlling PTP/1588 function */
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 105b0624081a..5b499130c3f5 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2982,6 +2982,54 @@ static s32 igb_init_i2c(struct igb_adapter *adapter)
return status;
}
+static ssize_t rx_drop_en_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+
+{
+ struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+ struct igb_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->rx_drop_enable)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t rx_drop_en_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ int queue_idx, reg_idx;
+ bool val;
+ u32 srrctl;
+ int ret;
+
+ ret = kstrtobool(buf, &val);
+ if (ret < 0)
+ return ret;
+
+ adapter->rx_drop_enable = val;
+
+ /* set for each currently active ring */
+ for (queue_idx = 0; queue_idx < adapter->num_rx_queues; queue_idx++) {
+ reg_idx = adapter->rx_ring[queue_idx]->reg_idx;
+ srrctl = rd32(E1000_SRRCTL(reg_idx));
+ if (val == 0)
+ srrctl &= ~E1000_SRRCTL_DROP_EN;
+ else
+ srrctl |= E1000_SRRCTL_DROP_EN;
+ wr32(E1000_SRRCTL(reg_idx), srrctl);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(rx_drop_en);
+
/**
* igb_probe - Device Initialization Routine
* @pdev: PCI device information struct
@@ -3329,6 +3377,9 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_eeprom;
}
+ /* Add adapter attributes */
+ device_create_file(&pdev->dev, &dev_attr_rx_drop_en);
+
/* let the f/w know that the h/w is now under the control of the
* driver.
*/
@@ -3655,6 +3706,9 @@ static void igb_remove(struct pci_dev *pdev)
*/
igb_release_hw_control(adapter);
+ /* Remove addapter attributes */
+ device_remove_file(&pdev->dev, &dev_attr_rx_drop_en);
+
#ifdef CONFIG_PCI_IOV
igb_disable_sriov(pdev);
#endif
@@ -3753,6 +3807,9 @@ static void igb_init_queue_configuration(struct igb_adapter *adapter)
max_rss_queues = igb_get_max_rss_queues(adapter);
adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus());
+ if (adapter->vfs_allocated_count || adapter->rss_queues > 1)
+ adapter->rx_drop_enable = true;
+
igb_set_flag_queue_pairs(adapter, max_rss_queues);
}
@@ -4504,7 +4561,8 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
if (hw->mac.type >= e1000_82580)
srrctl |= E1000_SRRCTL_TIMESTAMP;
/* Only set Drop Enable if we are supporting multiple queues */
- if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
+ if (adapter->rx_drop_enable &&
+ (adapter->vfs_allocated_count || adapter->num_rx_queues > 1))
srrctl |= E1000_SRRCTL_DROP_EN;
wr32(E1000_SRRCTL(reg_idx), srrctl);
--
2.18.0
^ permalink raw reply related
* Re: [PATCH net 1/3] taprio: Fix kernel panic in taprio_destroy
From: Vinicius Costa Gomes @ 2019-08-28 17:38 UTC (permalink / raw)
To: Vladimir Oltean
Cc: jhs, xiyou.wangcong, Jiri Pirko, David S. Miller, vedang.patel,
leandro.maciel.dorileo, netdev
In-Reply-To: <CA+h21hr7hZShmHfmF8XX3PpCKm_3FkYm=CzkBmyiYezWGR7kLw@mail.gmail.com>
Vladimir Oltean <olteanv@gmail.com> writes:
>> Personally, I would do things differently, I am thinking: adding the
>> taprio instance earlier to the list in taprio_init(), and keeping
>> taprio_destroy() the way it is now. But take this more as a suggestion
>> :-)
>>
>
> While I don't strongly oppose your proposal (keep the list removal
> unconditional, but match it better in placement to the list addition),
> I think it's rather fragile and I do see this bug recurring in the
> future. Anyway if you want to keep it "simpler" I can respin it like
> that.
>
I am thinking that keeping things "simpler" has the advantage of making
any bugs really loud and hopefully easier to catch.
Cheers,
--
Vinicius
^ permalink raw reply
* Re: [PATCH v2] riscv: add support for SECCOMP and SECCOMP_FILTER
From: Kees Cook @ 2019-08-25 21:59 UTC (permalink / raw)
To: David Abdurachmanov
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Oleg Nesterov,
Andy Lutomirski, Will Drewry, Shuah Khan, Alexei Starovoitov,
Daniel Borkmann, Martin KaFai Lau, Song Liu, Yonghong Song,
David Abdurachmanov, Thomas Gleixner, Allison Randal,
Alexios Zavras, Anup Patel, Vincent Chen, Alan Kao, linux-riscv,
linux-kernel, linux-kselftest, netdev, bpf, me
In-Reply-To: <20190822205533.4877-1-david.abdurachmanov@sifive.com>
On Thu, Aug 22, 2019 at 01:55:22PM -0700, David Abdurachmanov wrote:
> This patch was extensively tested on Fedora/RISCV (applied by default on
> top of 5.2-rc7 kernel for <2 months). The patch was also tested with 5.3-rc
> on QEMU and SiFive Unleashed board.
Oops, I see the mention of QEMU here. Where's the best place to find
instructions on creating a qemu riscv image/environment?
> There is one failing kernel selftest: global.user_notification_signal
This test has been fragile (and is not arch-specific), so as long as
everything else is passing, I would call this patch ready to go. :)
Reviewed-by: Kees Cook <keescook@chromium.org>
--
Kees Cook
^ permalink raw reply
* Re: [PATCH v2] riscv: add support for SECCOMP and SECCOMP_FILTER
From: Kees Cook @ 2019-08-26 17:48 UTC (permalink / raw)
To: David Abdurachmanov
Cc: Tycho Andersen, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Oleg Nesterov, Andy Lutomirski, Will Drewry, Shuah Khan,
Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu,
Yonghong Song, David Abdurachmanov, Thomas Gleixner,
Allison Randal, Alexios Zavras, Anup Patel, Vincent Chen,
Alan Kao, linux-riscv, linux-kernel, linux-kselftest, netdev, bpf,
me
In-Reply-To: <CAEn-LTrtn01=fp6taBBG_QkfBtgiJyt6oUjZJOi6VN8OeXp6=g@mail.gmail.com>
On Mon, Aug 26, 2019 at 09:39:50AM -0700, David Abdurachmanov wrote:
> I don't have the a build with SECCOMP for the board right now, so it
> will have to wait. I just finished a new kernel (almost rc6) for Fedora,
FWIW, I don't think this should block landing the code: all the tests
fail without seccomp support. ;) So this patch is an improvement!
--
Kees Cook
^ permalink raw reply
* Re: [PATCH v2] riscv: add support for SECCOMP and SECCOMP_FILTER
From: Kees Cook @ 2019-08-25 21:51 UTC (permalink / raw)
To: Paul Walmsley
Cc: David Abdurachmanov, Tycho Andersen, Palmer Dabbelt, Albert Ou,
Oleg Nesterov, Andy Lutomirski, Will Drewry, Shuah Khan,
Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu,
Yonghong Song, David Abdurachmanov, Thomas Gleixner,
Allison Randal, Alexios Zavras, Anup Patel, Vincent Chen,
Alan Kao, linux-riscv, linux-kernel, linux-kselftest, netdev, bpf,
me
In-Reply-To: <alpine.DEB.2.21.9999.1908231717550.25649@viisi.sifive.com>
On Fri, Aug 23, 2019 at 05:30:53PM -0700, Paul Walmsley wrote:
> On Thu, 22 Aug 2019, David Abdurachmanov wrote:
>
> > There is one failing kernel selftest: global.user_notification_signal
>
> Is this the only failing test? Or are the rest of the selftests skipped
> when this test fails, and no further tests are run, as seems to be shown
> here:
>
> https://lore.kernel.org/linux-riscv/CADnnUqcmDMRe1f+3jG8SPR6jRrnBsY8VVD70VbKEm0NqYeoicA@mail.gmail.com/
>
> For example, looking at the source, I'd naively expect to see the
> user_notification_closed_listener test result -- which follows right
> after the failing test in the selftest source. But there aren't any
> results?
>
> Also - could you follow up with the author of this failing test to see if
> we can get some more clarity about what might be going wrong here? It
> appears that the failing test was added in commit 6a21cc50f0c7f ("seccomp:
> add a return code to trap to userspace") by Tycho Andersen
> <tycho@tycho.ws>.
So, the original email says the riscv series is tested on top of 5.2-rc7,
but just for fun, can you confirm that you're building a tree that includes
9dd3fcb0ab73 ("selftests/seccomp: Handle namespace failures gracefully")? I
assume it does, but I suspect something similar is happening, where the
environment is slightly different than expected and the test stalls.
Does it behave the same way under emulation (i.e. can I hope to
reproduce this myself?)
--
Kees Cook
^ permalink raw reply
* RE: [PATCH v1 net-next] net: phy: mdio_bus: make mdiobus_scan also cover PHY that only talks C45
From: Voon, Weifeng @ 2019-08-28 17:36 UTC (permalink / raw)
To: Florian Fainelli, Ong, Boon Leong, Andrew Lunn
Cc: David S. Miller, Maxime Coquelin, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, Jose Abreu, Heiner Kallweit
In-Reply-To: <ef6aa10e-d3eb-e154-0168-d7f012858a2c@gmail.com>
> On 8/28/19 8:41 AM, Ong, Boon Leong wrote:
> >> On Tue, Aug 27, 2019 at 03:23:34PM +0000, Voon, Weifeng wrote:
> >>>>>> Make mdiobus_scan() to try harder to look for any PHY that only
> >>>> talks C45.
> >>>>> If you are not using Device Tree or ACPI, and you are letting the
> >>>>> MDIO bus be scanned, it sounds like there should be a way for you
> >>>>> to provide a hint as to which addresses should be scanned (that's
> >>>>> mii_bus::phy_mask) and possibly enhance that with a mask of
> >>>>> possible
> >>>>> C45 devices?
> >>>>
> >>>> Yes, i don't like this unconditional c45 scanning. A lot of MDIO
> >>>> bus drivers don't look for the MII_ADDR_C45. They are going to do a
> >>>> C22 transfer, and maybe not mask out the MII_ADDR_C45 from reg,
> >>>> causing an invalid register write. Bad things can then happen.
> >>>>
> >>>> With DT and ACPI, we have an explicit indication that C45 should be
> >>>> used, so we know on this platform C45 is safe to use. We need
> >>>> something similar when not using DT or ACPI.
> >>>>
> >>>> Andrew
> >>>
> >>> Florian and Andrew,
> >>> The mdio c22 is using the start-of-frame ST=01 while mdio c45 is
> >>> using ST=00 as identifier. So mdio c22 device will not response to
> mdio c45 protocol.
> >>> As in IEEE 802.1ae-2002 Annex 45A.3 mention that:
> >>> " Even though the Clause 45 MDIO frames using the ST=00 frame code
> >>> will also be driven on to the Clause 22 MII Management interface,
> >>> the Clause 22 PHYs will ignore the frames. "
> >>>
> >>> Hence, I am not seeing any concern that the c45 scanning will mess
> >>> up with
> >>> c22 devices.
> >>
> >> Hi Voon
> >>
> >> Take for example mdio-hisi-femac.c
> >>
> >> static int hisi_femac_mdio_read(struct mii_bus *bus, int mii_id, int
> >> regnum) {
> >> struct hisi_femac_mdio_data *data = bus->priv;
> >> int ret;
> >>
> >> ret = hisi_femac_mdio_wait_ready(data);
> >> if (ret)
> >> return ret;
> >>
> >> writel((mii_id << BIT_PHY_ADDR_OFFSET) | regnum,
> >> data->membase + MDIO_RWCTRL);
> >>
> >>
> >> There is no check here for MII_ADDR_C45. So it will perform a C22
> >> transfer. And regnum will still have MII_ADDR_C45 in it, so the
> >> writel() is going to set bit 30, since #define MII_ADDR_C45 (1<<30).
> >> What happens on this hardware under these conditions?
> >>
> >> You cannot unconditionally ask an MDIO driver to do a C45 transfer.
> >> Some drivers are going to do bad things.
> >
> > Andrew & Florian, thanks for your review on this patch and insights on
> it.
> > We will look into the implementation as suggested as follow.
> >
> > - for each bit clear in mii_bus::phy_mask, scan it as C22
> > - for each bit clear in mii_bus::phy_c45_mask, scan it as C45
> >
> > We will work on this and resubmit soonest.
>
> Sounds good. If you do not need to scan the MDIO bus, another approach
> is to call get_phy_device() by passing the is_c45 boolean to true in
> order to connect directly to a C45 device for which you already know the
> address.
>
> Assuming this is done for the stmmac PCI changes that you have submitted,
> and that those cards have a fixed set of addresses for their PHYs, maybe
> scanning the bus is overkill?
> --
> Florian
Good suggestion. And yes, we have a fix phy address too. But the MAC is free
to pair with any PHY which might supports only mdio c22 or only mdio c45.
We will consider it and resubmit soonest.
^ permalink raw reply
* [PATCH net v1] net/sched: cbs: Fix not adding cbs instance to list
From: Vinicius Costa Gomes @ 2019-08-28 17:36 UTC (permalink / raw)
To: netdev; +Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri, olteanv
When removing a cbs instance when offloading is enabled, the crash
below can be observed. Also, the current code doesn't handle correctly
the case when offload is disabled without removing the qdisc: if the
link speed changes the credit calculations will be wrong.
The solution for both issues is the same, add the cbs instance being
created unconditionally to the global list, even if the link state
notification isn't useful "right now".
Crash log:
[ 59.838566] BUG: kernel NULL pointer dereference, address: 0000000000000000
[ 59.838570] #PF: supervisor read access in kernel mode
[ 59.838571] #PF: error_code(0x0000) - not-present page
[ 59.838572] PGD 0 P4D 0
[ 59.838574] Oops: 0000 [#1] SMP PTI
[ 59.838576] CPU: 4 PID: 492 Comm: tc Not tainted 5.3.0-rc6+ #5
[ 59.838577] Hardware name: Gigabyte Technology Co., Ltd. Z390 AORUS ULTRA/Z390 AORUS ULTRA-CF, BIOS F7 03/14/2019
[ 59.838581] RIP: 0010:__list_del_entry_valid+0x29/0xa0
[ 59.838583] Code: 90 48 b8 00 01 00 00 00 00 ad de 55 48 8b 17 4c 8b 47 08 48 89 e5 48 39 c2 74 27 48 b8 22 01 00 00 00 00 ad de 49 39 c0 74 2d <49> 8b 30 48 39 fe 75 3d 48 8b 52 08 48 39 f2 75 4c b8 01 00 00 00
[ 59.838585] RSP: 0018:ffffbba040a47988 EFLAGS: 00010217
[ 59.838587] RAX: dead000000000122 RBX: ffff9f356410cc00 RCX: 0000000000000000
[ 59.838588] RDX: 0000000000000000 RSI: ffff9f356410cc64 RDI: ffff9f356410cde0
[ 59.838589] RBP: ffffbba040a47988 R08: 0000000000000000 R09: ffffbba040a47a34
[ 59.838591] R10: 0000000000000000 R11: ffffbba040a47aa0 R12: ffff9f3569aa0000
[ 59.838592] R13: ffff9f356410cd40 R14: 0000000000000000 R15: 0000000000000000
[ 59.838593] FS: 00007f88b2822f80(0000) GS:ffff9f356e100000(0000) knlGS:0000000000000000
[ 59.838595] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 59.838596] CR2: 0000000000000000 CR3: 00000004a0b0c004 CR4: 00000000003606e0
[ 59.838597] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 59.838598] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 59.838599] Call Trace:
[ 59.838603] cbs_destroy+0x32/0xa0 [sch_cbs]
[ 59.838605] qdisc_destroy+0x45/0x120
[ 59.838607] qdisc_put+0x25/0x30
[ 59.838608] qdisc_graft+0x2c1/0x450
[ 59.838610] tc_get_qdisc+0x1c8/0x310
[ 59.838612] ? prep_new_page+0x40/0xc0
[ 59.838614] rtnetlink_rcv_msg+0x293/0x360
[ 59.838616] ? kmem_cache_alloc_node_trace+0x177/0x290
[ 59.838617] ? __kmalloc_node_track_caller+0x38/0x50
[ 59.838619] ? rtnl_calcit.isra.0+0xf0/0xf0
[ 59.838621] netlink_rcv_skb+0x48/0x110
[ 59.838623] rtnetlink_rcv+0x10/0x20
[ 59.838624] netlink_unicast+0x15b/0x1d0
[ 59.838625] netlink_sendmsg+0x1fb/0x3a0
[ 59.838628] sock_sendmsg+0x2f/0x40
[ 59.838629] ___sys_sendmsg+0x295/0x2f0
[ 59.838631] ? ___sys_recvmsg+0x151/0x1e0
[ 59.838633] ? do_wp_page+0x7c/0x450
[ 59.838634] __sys_sendmsg+0x48/0x80
[ 59.838636] __x64_sys_sendmsg+0x1a/0x20
[ 59.838638] do_syscall_64+0x53/0x1e0
[ 59.838640] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 59.838641] RIP: 0033:0x7f88b2aab69a
[ 59.838643] Code: 48 c7 c0 ff ff ff ff eb be 0f 1f 80 00 00 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 18 b8 2e 00 00 00 c5 fc 77 0f 05 <48> 3d 00 f0 ff ff 77 5e c3 0f 1f 44 00 00 48 83 ec 28 89 54 24 1c
[ 59.838645] RSP: 002b:00007fff79f253d8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
[ 59.838647] RAX: ffffffffffffffda RBX: 000055bfdd1c19a0 RCX: 00007f88b2aab69a
[ 59.838648] RDX: 0000000000000000 RSI: 00007fff79f25448 RDI: 0000000000000003
[ 59.838649] RBP: 00007fff79f254b0 R08: 0000000000000001 R09: 000055bfddc268a0
[ 59.838650] R10: 0000000000000000 R11: 0000000000000246 R12: 000000005d66a666
[ 59.838652] R13: 0000000000000000 R14: 00007fff79f25550 R15: 00007fff79f25530
[ 59.838653] Modules linked in: sch_cbs sch_mqprio e1000e igb intel_pch_thermal thermal video backlight
[ 59.838657] CR2: 0000000000000000
[ 59.838658] ---[ end trace 08db7a13640831a0 ]---
[ 59.838660] RIP: 0010:__list_del_entry_valid+0x29/0xa0
[ 59.838662] Code: 90 48 b8 00 01 00 00 00 00 ad de 55 48 8b 17 4c 8b 47 08 48 89 e5 48 39 c2 74 27 48 b8 22 01 00 00 00 00 ad de 49 39 c0 74 2d <49> 8b 30 48 39 fe 75 3d 48 8b 52 08 48 39 f2 75 4c b8 01 00 00 00
[ 59.838664] RSP: 0018:ffffbba040a47988 EFLAGS: 00010217
[ 59.838665] RAX: dead000000000122 RBX: ffff9f356410cc00 RCX: 0000000000000000
[ 59.838666] RDX: 0000000000000000 RSI: ffff9f356410cc64 RDI: ffff9f356410cde0
[ 59.838667] RBP: ffffbba040a47988 R08: 0000000000000000 R09: ffffbba040a47a34
[ 59.838669] R10: 0000000000000000 R11: ffffbba040a47aa0 R12: ffff9f3569aa0000
[ 59.838670] R13: ffff9f356410cd40 R14: 0000000000000000 R15: 0000000000000000
[ 59.838671] FS: 00007f88b2822f80(0000) GS:ffff9f356e100000(0000) knlGS:0000000000000000
[ 59.838673] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 59.838674] CR2: 0000000000000000 CR3: 00000004a0b0c004 CR4: 00000000003606e0
[ 59.838675] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 59.838676] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Fixes: e0a7683 ("net/sched: cbs: fix port_rate miscalculation")
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
net/sched/sch_cbs.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c
index 732e109..a167bda 100644
--- a/net/sched/sch_cbs.c
+++ b/net/sched/sch_cbs.c
@@ -401,6 +401,10 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt,
if (!q->qdisc)
return -ENOMEM;
+ spin_lock(&cbs_list_lock);
+ list_add(&q->cbs_list, &cbs_list);
+ spin_unlock(&cbs_list_lock);
+
qdisc_hash_add(q->qdisc, false);
q->queue = sch->dev_queue - netdev_get_tx_queue(dev, 0);
@@ -414,12 +418,6 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt,
if (err)
return err;
- if (!q->offload) {
- spin_lock(&cbs_list_lock);
- list_add(&q->cbs_list, &cbs_list);
- spin_unlock(&cbs_list_lock);
- }
-
return 0;
}
@@ -428,15 +426,18 @@ static void cbs_destroy(struct Qdisc *sch)
struct cbs_sched_data *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
- spin_lock(&cbs_list_lock);
- list_del(&q->cbs_list);
- spin_unlock(&cbs_list_lock);
+ /* Nothing to do if we couldn't create the underlying qdisc */
+ if (!q->qdisc)
+ return;
qdisc_watchdog_cancel(&q->watchdog);
cbs_disable_offload(dev, q);
- if (q->qdisc)
- qdisc_put(q->qdisc);
+ spin_lock(&cbs_list_lock);
+ list_del(&q->cbs_list);
+ spin_unlock(&cbs_list_lock);
+
+ qdisc_put(q->qdisc);
}
static int cbs_dump(struct Qdisc *sch, struct sk_buff *skb)
--
2.23.0
^ permalink raw reply related
* [RFC net-next v1 0/5] PHY converter driver for DW xPCS IP
From: Ong Boon Leong @ 2019-08-28 17:33 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
Following review comment from Florian and discussion in below thread:-
https://patchwork.ozlabs.org/patch/1109777/
This RFC is to solicit feedback on the implementation of PHY converter
driver for DW xPCS and some changes in the mdiobus API to prepare for
mdio device registration during driver open() instead of probe() phase
for non-DT platform. The implementation in this Phy Converter has DT
registration for future expansion, however, it is not tested in our
current platform.
The 1st three patches involve changes in existing mdiobus API:-
1) Make mdiobus_create_device() function callable from Ethernet driver
2) Introduce new API mdiobus_get_mdio_device()
3) Add private data for struct mdio_device so that DW xPCS specific
private data can be established between the pairing Ethernet
controller for non-DT way.
The reason for changes for mdiobus_create_device() &
mdiobus_get_mdio_device() is to allow Eth driver to be able to create
mdio device for PHY converter driver when Ethernet driver open() is
called. Existing way for registering mdio device for non-DT appraoch
is through mdiobus_register_board_info() and the mdio device creation
happens inside Ethernet probe() whereby IRQ is not setup. The mdio
device registration happens in mdiobus_register() -->
mdiobus_setup_mdiodevfrom_board_info(), and it becomes an issue for
Phy Converter such as dwxpcs that requires IRQ setup before, i.e.
inside Ethernet controller open().
The 4th patch is for PHY Converter driver for DW xPCS.
Large portion of main logics of this code has been reviewed in the
past in above review thread and all review inputs have been factored.
First, the loading of PHY converter driver is through ACPI Device ID.
The current implementation also has logics for DT style, but since
we don't have such platform, we the DT implementation as place-holder
for anyone that needs in future. The DT implementation follows the
design of drivers/net/phy/xilinx_gmii2rgmii.c closely.
What is extra is setup for DW xPCS IRQ request. In current EHL & TGL
implementation, the IRQ is routed from MAC controller. For non-DT way,
the IRQ line is tied to Ethernet driver (PCI enum), and we need a
way to pass IRQ info from Ethernet driver to PHY converter driver
during the creation of mdio device. Therefore, this is the reason
for the 1st 3 patches. All the ISR does is to kick the workqueue to
process the IRQ as we cannot call mdio_read() and mdio_write() inside
ISR.
The 5th (last) patch shows how the associated PHY converter mdio device
is setup in Ethernet controller open() function and removed during
stop(). The implementation is done in stmmac pci driver.
With this implementation, now, we have dwxpcs implemented as PHY driver
and the hook from stmmac driver for non-DT style is done through
platform-specific data related to EHL & TGL when SGMII interface is
selected. The PHY converter driver will still be beneficial for other
platform that would need it and may use DT to enable the PHY converter
driver and mdio device through DT definition.
Please kindly review this RFC and provide any feedback/concern that
the community may have. Appreciate your time here.
Thanks
Boon Leong
Ong Boon Leong (5):
net: phy: make mdiobus_create_device() function callable from Eth
driver
net: phy: introduce mdiobus_get_mdio_device
net: phy: add private data to mdio_device
net: phy: introducing support for DWC xPCS logics for EHL & TGL
net: stmmac: add dwxpcs boardinfo for mdio_device registration
drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 +
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 25 ++
.../net/ethernet/stmicro/stmmac/stmmac_pci.c | 45 +-
drivers/net/phy/Kconfig | 9 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/dwxpcs.c | 417 ++++++++++++++++++
drivers/net/phy/mdio_bus.c | 11 +-
include/linux/dwxpcs.h | 16 +
include/linux/mdio.h | 3 +
include/linux/phy.h | 7 +
include/linux/stmmac.h | 3 +
12 files changed, 537 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/phy/dwxpcs.c
create mode 100644 include/linux/dwxpcs.h
--
2.17.0
^ permalink raw reply
* [RFC net-next v1 4/5] net: phy: introducing support for DWC xPCS logics for EHL & TGL
From: Ong Boon Leong @ 2019-08-28 17:33 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828173321.25334-1-boon.leong.ong@intel.com>
xPCS is DWC Ethernet Physical Coding Sublayer that can be integrated with
Ethernet MAC controller and acts as converter between GMII and SGMII. An
example is as shown below whereby DWC xPCS is integrated with DW EQoS MAC
to form GbE Controller.
<-----------------GbE Controller---------->|<--External PHY chip-->
+----------+ +----+ +---+ +--------------+
| EQoS | <-GMII->| DW |<-->|PHY| <-- SGMII --> | External GbE |
| MAC | |xPCS| |IF | | PHY Chip |
+----------+ +----+ +---+ +--------------+
^ ^ ^
| | |
+---------------------MDIO-------------------------+
xPCS is a Clause-45 MDIO Manageable Device (MMD) and supports basic
functionalities for initializing xPCS and configuring auto negotiation(AN),
loopback, link status, AN advertisement and Link Partner ability are
implemented. The implementation supports the C37 AN for 1000BASE-X and
SGMII (MAC side SGMII only).
Tested-by: Tan, Tee Min <tee.min.tan@intel.com>
Reviewed-by: Voon Weifeng <weifeng.voon@intel.com>
Reviewed-by: Kweh Hock Leong <hock.leong.kweh@intel.com>
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
drivers/net/phy/Kconfig | 9 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/dwxpcs.c | 417 +++++++++++++++++++++++++++++++++++++++
include/linux/dwxpcs.h | 16 ++
4 files changed, 443 insertions(+)
create mode 100644 drivers/net/phy/dwxpcs.c
create mode 100644 include/linux/dwxpcs.h
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 03be30cde552..fd037f5366d8 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -364,6 +364,15 @@ config DP83867_PHY
---help---
Currently supports the DP83867 PHY.
+config DWXPCS
+ tristate "Synopsys DesignWare PCS converter driver"
+ help
+ This driver supports DW PCS IP that provides the Serial Gigabit
+ Media Independent Interface(SGMII) between Ethernet physical media
+ devices and the Gigabit Ethernet controller.
+
+ Currently tested with stmmac.
+
config FIXED_PHY
tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index a03437e091f3..5def985ae3ca 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_DP83822_PHY) += dp83822.o
obj-$(CONFIG_DP83TC811_PHY) += dp83tc811.o
obj-$(CONFIG_DP83848_PHY) += dp83848.o
obj-$(CONFIG_DP83867_PHY) += dp83867.o
+obj-$(CONFIG_DWXPCS) += dwxpcs.o
obj-$(CONFIG_FIXED_PHY) += fixed_phy.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o
diff --git a/drivers/net/phy/dwxpcs.c b/drivers/net/phy/dwxpcs.c
new file mode 100644
index 000000000000..f0003cec6871
--- /dev/null
+++ b/drivers/net/phy/dwxpcs.c
@@ -0,0 +1,417 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Intel Corporation.
+ * DWC Ethernet Physical Coding Sublayer for GMII2SGMII Converter
+ */
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/dwxpcs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+
+/* XPCS MII MMD Device Addresses */
+#define XPCS_MDIO_MII_MMD MDIO_MMD_VEND2
+
+/* MII MMD registers offsets */
+#define MDIO_MII_MMD_DIGITAL_CTRL_1 0x8000 /* Digital Control 1 */
+#define MDIO_MII_MMD_AN_CTRL 0x8001 /* AN Control */
+#define MDIO_MII_MMD_AN_STAT 0x8002 /* AN Status */
+
+/* MII MMD SR AN Advertisement & Link Partner Ability are slightly
+ * different from MII_ADVERTISEMENT & MII_LPA in below fields:
+ */
+#define MDIO_MII_MMD_HD BIT(6) /* Half duplex */
+#define MDIO_MII_MMD_FD BIT(5) /* Full duplex */
+#define MDIO_MII_MMD_PSE_SHIFT 7 /* Pause Ability shift */
+#define MDIO_MII_MMD_PSE GENMASK(8, 7) /* Pause Ability */
+#define MDIO_MII_MMD_PSE_NO 0x0
+#define MDIO_MII_MMD_PSE_ASYM 0x1
+#define MDIO_MII_MMD_PSE_SYM 0x2
+#define MDIO_MII_MMD_PSE_BOTH 0x3
+
+/* Automatic Speed Mode Change for MAC side SGMII AN */
+#define MDIO_MII_MMD_DIGI_CTRL_1_MAC_AUTO_SW BIT(9)
+
+/* MII MMD AN Control defines */
+#define MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT 3 /* TX Config shift */
+#define AN_CTRL_TX_CONF_PHY_SIDE_SGMII 0x1 /* PHY side SGMII mode */
+#define AN_CTRL_TX_CONF_MAC_SIDE_SGMII 0x0 /* MAC side SGMII mode */
+#define MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT 1 /* PCS Mode shift */
+#define MDIO_MII_MMD_AN_CTRL_PCS_MD GENMASK(2, 1) /* PCS Mode */
+#define AN_CTRL_PCS_MD_C37_1000BASEX 0x0 /* C37 AN for 1000BASE-X */
+#define AN_CTRL_PCS_MD_C37_SGMII 0x2 /* C37 AN for SGMII */
+#define MDIO_MII_MMD_AN_CTRL_AN_INTR_EN BIT(0) /* AN Complete Intr Enable */
+
+/* MII MMD AN Status defines for SGMII AN Status */
+#define AN_STAT_C37_AN_CMPLT BIT(0) /* AN Complete Intr */
+#define AN_STAT_SGMII_AN_FD BIT(1) /* Full Duplex */
+#define AN_STAT_SGMII_AN_SPEED_SHIFT 2 /* AN Speed shift */
+#define AN_STAT_SGMII_AN_SPEED GENMASK(3, 2) /* AN Speed */
+#define AN_STAT_SGMII_AN_10MBPS 0x0 /* 10 Mbps */
+#define AN_STAT_SGMII_AN_100MBPS 0x1 /* 100 Mbps */
+#define AN_STAT_SGMII_AN_1000MBPS 0x2 /* 1000 Mbps */
+#define AN_STAT_SGMII_AN_LNKSTS BIT(4) /* Link Status */
+
+enum dwxpcs_state_t {
+ __DWXPCS_REMOVING,
+ __DWXPCS_TASK_SCHED,
+};
+
+struct pcs_stats {
+ int link;
+ int speed;
+ int duplex;
+};
+
+struct dwxpcs_priv {
+ struct phy_device *phy_dev;
+ struct phy_driver *phy_drv;
+ struct phy_device cached_phy_dev;
+ struct phy_driver conv_phy_drv;
+ struct mdio_device *mdiodev;
+ struct pcs_stats stats;
+ struct dwxpcs_platform_data *pdata;
+ char int_name[IFNAMSIZ];
+ unsigned long state;
+ struct workqueue_struct *int_wq;
+ struct work_struct an_task;
+};
+
+/* DW xPCS mdiobus_read and mdiobus_write helper functions */
+#define xpcs_read(dev, reg) \
+ mdiobus_read(bus, xpcs_addr, \
+ MII_ADDR_C45 | (reg) | \
+ ((dev) << MII_DEVADDR_C45_SHIFT))
+#define xpcs_write(dev, reg, val) \
+ mdiobus_write(bus, xpcs_addr, \
+ MII_ADDR_C45 | (reg) | \
+ ((dev) << MII_DEVADDR_C45_SHIFT), val)
+
+static void dwxpcs_init(struct dwxpcs_priv *priv)
+{
+ struct mii_bus *bus = priv->mdiodev->bus;
+ int xpcs_addr = priv->mdiodev->addr;
+ int pcs_mode = priv->pdata->mode;
+ int phydata;
+
+ if (pcs_mode == DWXPCS_MODE_SGMII_AN) {
+ /* For AN for SGMII mode, the settings are :-
+ * 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
+ * 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
+ * DW xPCS used with DW EQoS MAC is always MAC
+ * side SGMII.
+ * 3) VR_MII_AN_CTRL Bit(0) [AN_INTR_EN] = 1b (AN Interrupt
+ * enabled)
+ * 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
+ * speed/duplex mode change by HW after SGMII AN complete)
+ * Note: Since it is MAC side SGMII, there is no need to set
+ * SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config
+ * from PHY about the link state change after C28 AN
+ * is completed between PHY and Link Partner.
+ */
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_CTRL);
+ phydata &= ~MDIO_MII_MMD_AN_CTRL_PCS_MD;
+
+ phydata |= MDIO_MII_MMD_AN_CTRL_AN_INTR_EN |
+ (AN_CTRL_PCS_MD_C37_SGMII <<
+ MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT &
+ MDIO_MII_MMD_AN_CTRL_PCS_MD) |
+ (AN_CTRL_TX_CONF_MAC_SIDE_SGMII <<
+ MDIO_MII_MMD_AN_CTRL_TX_CONFIG_SHIFT);
+ xpcs_write(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_CTRL, phydata);
+
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD,
+ MDIO_MII_MMD_DIGITAL_CTRL_1);
+ phydata |= MDIO_MII_MMD_DIGI_CTRL_1_MAC_AUTO_SW;
+ xpcs_write(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_DIGITAL_CTRL_1,
+ phydata);
+ } else {
+ /* For AN for 1000BASE-X mode, the settings are :-
+ * 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 00b (1000BASE-X C37)
+ * 2) VR_MII_AN_CTRL Bit(0) [AN_INTR_EN] = 1b (AN Interrupt
+ * enabled)
+ * 3) SR_MII_AN_ADV Bit(6)[FD] = 1b (Full Duplex)
+ * Note: Half Duplex is rarely used, so don't advertise.
+ * 4) SR_MII_AN_ADV Bit(8:7)[PSE] = 11b (Sym & Asym Pause)
+ */
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_CTRL);
+ phydata &= ~MDIO_MII_MMD_AN_CTRL_PCS_MD;
+ phydata |= MDIO_MII_MMD_AN_CTRL_AN_INTR_EN |
+ (AN_CTRL_PCS_MD_C37_1000BASEX <<
+ MDIO_MII_MMD_AN_CTRL_PCS_MD_SHIFT &
+ MDIO_MII_MMD_AN_CTRL_PCS_MD);
+ xpcs_write(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_CTRL, phydata);
+
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD, MII_ADVERTISE);
+ phydata |= MDIO_MII_MMD_FD |
+ (MDIO_MII_MMD_PSE_BOTH << MDIO_MII_MMD_PSE_SHIFT);
+ xpcs_write(XPCS_MDIO_MII_MMD, MII_ADVERTISE, phydata);
+ }
+}
+
+static int dwxpcs_read_status(struct phy_device *phydev)
+{
+ struct dwxpcs_priv *priv = (struct dwxpcs_priv *)phydev->priv;
+ struct mii_bus *bus = priv->mdiodev->bus;
+ int xpcs_addr = priv->mdiodev->addr;
+ int pcs_mode = priv->pdata->mode;
+ int phydata;
+ int err;
+
+ if (priv->phy_drv->read_status)
+ err = priv->phy_drv->read_status(phydev);
+ else
+ err = genphy_read_status(phydev);
+
+ if (err < 0)
+ return err;
+
+ /* For SGMII AN, we are done as the speed/duplex are automatically
+ * set because we have initialized 'MAC_AUTO_SW' for MAC side SGMII.
+ */
+ if (pcs_mode == DWXPCS_MODE_1000BASEX_AN) {
+ /* For 1000BASE-X AN, we need to adjust duplex mode according
+ * to link partner. No need to update speed as it is always
+ * 1000Mbps.
+ */
+ phydata = xpcs_read(XPCS_MDIO_MII_MMD, MII_BMCR);
+ phydata &= ~BMCR_FULLDPLX;
+ phydata |= phydev->duplex ? BMCR_FULLDPLX : 0;
+ xpcs_write(XPCS_MDIO_MII_MMD, MII_BMCR, phydata);
+ }
+
+ return 0;
+}
+
+static void dwxpcs_get_linkstatus(struct dwxpcs_priv *priv, int an_stat)
+{
+ struct mii_bus *bus = priv->mdiodev->bus;
+ struct pcs_stats *stats = &priv->stats;
+ int xpcs_addr = priv->mdiodev->addr;
+ int pcs_mode = priv->pdata->mode;
+
+ if (pcs_mode == DWXPCS_MODE_SGMII_AN) {
+ /* Check the SGMII AN link status */
+ if (an_stat & AN_STAT_SGMII_AN_LNKSTS) {
+ int speed_value;
+
+ stats->link = 1;
+
+ speed_value = ((an_stat & AN_STAT_SGMII_AN_SPEED) >>
+ AN_STAT_SGMII_AN_SPEED_SHIFT);
+ if (speed_value == AN_STAT_SGMII_AN_1000MBPS)
+ stats->speed = SPEED_1000;
+ else if (speed_value == AN_STAT_SGMII_AN_100MBPS)
+ stats->speed = SPEED_100;
+ else
+ stats->speed = SPEED_10;
+
+ if (an_stat & AN_STAT_SGMII_AN_FD)
+ stats->duplex = 1;
+ else
+ stats->duplex = 0;
+ } else {
+ stats->link = 0;
+ }
+ } else if (pcs_mode == DWXPCS_MODE_1000BASEX_AN) {
+ /* For 1000BASE-X AN, 1000BASE-X is always 1000Mbps.
+ * For duplex mode, we read from BMCR_FULLDPLX which is
+ * only valid if BMCR_ANENABLE is not enabeld.
+ */
+ int phydata = xpcs_read(XPCS_MDIO_MII_MMD, MII_BMCR);
+
+ stats->link = 1;
+ stats->speed = SPEED_1000;
+ if (!(phydata & BMCR_ANENABLE))
+ stats->duplex = phydata & BMCR_FULLDPLX ? 1 : 0;
+ }
+}
+
+static void dwxpcs_irq_handle(struct dwxpcs_priv *priv)
+{
+ struct mii_bus *bus = priv->mdiodev->bus;
+ struct device *dev = &priv->mdiodev->dev;
+ int xpcs_addr = priv->mdiodev->addr;
+ int an_stat;
+
+ /* AN status */
+ an_stat = xpcs_read(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_STAT);
+
+ if (an_stat & AN_STAT_C37_AN_CMPLT) {
+ struct pcs_stats *stats = &priv->stats;
+
+ dwxpcs_get_linkstatus(priv, an_stat);
+
+ /* Clear C37 AN complete status by writing zero */
+ xpcs_write(XPCS_MDIO_MII_MMD, MDIO_MII_MMD_AN_STAT, 0);
+
+ dev_info(dev, "%s: Link = %d - %d/%s\n",
+ __func__,
+ stats->link,
+ stats->speed,
+ stats->duplex ? "Full" : "Half");
+ }
+}
+
+static void dwxpcs_an_task(struct work_struct *work)
+{
+ struct dwxpcs_priv *priv = container_of(work,
+ struct dwxpcs_priv,
+ an_task);
+ dwxpcs_irq_handle(priv);
+
+ clear_bit(__DWXPCS_TASK_SCHED, &priv->state);
+}
+
+static irqreturn_t dwxpcs_interrupt(int irq, void *dev_id)
+{
+ struct dwxpcs_priv *priv = (struct dwxpcs_priv *)dev_id;
+
+ /* Handle the clearing of AN status outside of interrupt context
+ * as it involves mdiobus_read() & mdiobus_write().
+ */
+ if (!test_bit(__DWXPCS_REMOVING, &priv->state) &&
+ !test_and_set_bit(__DWXPCS_TASK_SCHED, &priv->state)) {
+ queue_work(priv->int_wq, &priv->an_task);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id dwxpcs_acpi_match[] = {
+ { "INTC1033" }, /* EHL Ethernet PCS */
+ { "INTC1034" }, /* TGL Ethernet PCS */
+ { },
+};
+
+MODULE_DEVICE_TABLE(acpi, dwxpcs_acpi_match);
+#endif // CONFIG_ACPI
+
+static int dwxpcs_probe(struct mdio_device *mdiodev)
+{
+ struct device_node *phy_node;
+ struct dwxpcs_priv *priv;
+ struct device_node *np;
+ struct device *dev;
+ int ret;
+
+ dev = &mdiodev->dev;
+ np = dev->of_node;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (np) {
+ /* Handle mdio_device registered through devicetree */
+ phy_node = of_parse_phandle(np, "phy-handle", 0);
+ if (!phy_node) {
+ dev_err(dev, "Couldn't parse phy-handle\n");
+ return -ENODEV;
+ }
+
+ priv->phy_dev = of_phy_find_device(phy_node);
+ of_node_put(phy_node);
+ if (!priv->phy_dev) {
+ dev_info(dev, "Couldn't find phydev\n");
+ return -EPROBE_DEFER;
+ }
+ } else {
+ /* Handle mdio_device registered through mdio_board_info */
+ priv->pdata = (struct dwxpcs_platform_data *)dev->platform_data;
+
+ priv->phy_dev = mdiobus_get_phy(mdiodev->bus,
+ priv->pdata->ext_phy_addr);
+ }
+
+ if (!priv->phy_dev) {
+ dev_info(dev, "Couldn't find phydev\n");
+ return -EPROBE_DEFER;
+ }
+
+ if (!priv->phy_dev->drv) {
+ dev_info(dev, "Attached phy not ready\n");
+ return -EPROBE_DEFER;
+ }
+
+ priv->mdiodev = mdiodev;
+
+ /* Initialize DW XPCS */
+ dwxpcs_init(priv);
+
+ priv->phy_drv = priv->phy_dev->drv;
+ memcpy(&priv->conv_phy_drv, priv->phy_dev->drv,
+ sizeof(struct phy_driver));
+ priv->conv_phy_drv.read_status = dwxpcs_read_status;
+ /* Store a copy of phy_dev info for remove() later */
+ priv->cached_phy_dev.priv = priv->phy_dev->priv;
+ priv->cached_phy_dev.drv = priv->phy_dev->drv;
+ priv->phy_dev->priv = priv;
+ priv->phy_dev->drv = &priv->conv_phy_drv;
+
+ if (priv->pdata->irq > 0) {
+ char *int_name;
+
+ INIT_WORK(&priv->an_task, dwxpcs_an_task);
+ clear_bit(__DWXPCS_TASK_SCHED, &priv->state);
+
+ int_name = priv->int_name;
+ sprintf(int_name, "%s-%d", "dwxpcs", priv->mdiodev->dev.id);
+ priv->int_wq = create_singlethread_workqueue(int_name);
+ if (!priv->int_wq) {
+ dev_err(dev, "%s: Failed to create workqueue\n",
+ int_name);
+ return -ENOMEM;
+ }
+
+ ret = request_irq(priv->pdata->irq, dwxpcs_interrupt,
+ IRQF_SHARED, int_name, priv);
+ if (unlikely(ret < 0)) {
+ destroy_workqueue(priv->int_wq);
+ dev_err(dev, "%s: Allocating DW XPCS IRQ %d (%d)\n",
+ __func__, priv->pdata->irq, ret);
+ return ret;
+ }
+ }
+ dev_info(dev, "%s: DW XPCS mdio device (IRQ: %d) probed successful\n",
+ __func__, priv->pdata->irq);
+
+ mdiodev->priv = priv;
+
+ return 0;
+}
+
+static void dwxpcs_remove(struct mdio_device *mdiodev)
+{
+ struct dwxpcs_priv *priv = (struct dwxpcs_priv *)mdiodev->priv;
+
+ set_bit(__DWXPCS_REMOVING, &priv->state);
+
+ /* Restore the original phy_device info */
+ priv->phy_dev->priv = priv->cached_phy_dev.priv;
+ priv->phy_dev->drv = priv->cached_phy_dev.drv;
+
+ free_irq(priv->pdata->irq, priv);
+ if (priv->int_wq)
+ destroy_workqueue(priv->int_wq);
+}
+
+static struct mdio_driver dwxpcs_driver = {
+ .probe = dwxpcs_probe,
+ .remove = dwxpcs_remove,
+ .mdiodrv.driver = {
+ .name = "dwxpcs",
+ .acpi_match_table = ACPI_PTR(dwxpcs_acpi_match),
+ },
+};
+
+mdio_module_driver(dwxpcs_driver);
+
+MODULE_DESCRIPTION("DW xPCS converter driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/dwxpcs.h b/include/linux/dwxpcs.h
new file mode 100644
index 000000000000..2082e800ee04
--- /dev/null
+++ b/include/linux/dwxpcs.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_DWXPCS_H
+#define __LINUX_DWXPCS_H
+
+enum dwxpcs_pcs_mode {
+ DWXPCS_MODE_SGMII_AN,
+ DWXPCS_MODE_1000BASEX_AN,
+};
+
+struct dwxpcs_platform_data {
+ int irq;
+ enum dwxpcs_pcs_mode mode;
+ int ext_phy_addr;
+};
+
+#endif
--
2.17.0
^ permalink raw reply related
* [RFC net-next v1 5/5] net: stmmac: add dwxpcs boardinfo for mdio_device registration
From: Ong Boon Leong @ 2019-08-28 17:33 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828173321.25334-1-boon.leong.ong@intel.com>
For EHL & TGL Ethernet PCS, the mdio bus address is the same across all
TSN controller instances. External PHY is using default mdio bus address of
0x0. As Ethernet DW PCS is only applicable for SGMII interface, we only
register setup_intel_mgbe_phy_conv() for all TSN controller with SGMII
interface only.
Also introduce callback for remove mdio_device for unloading driver.
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 +
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 25 +++++++++++
.../net/ethernet/stmicro/stmmac/stmmac_pci.c | 45 ++++++++++++++++++-
include/linux/stmmac.h | 3 ++
5 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 2325b40dff6e..db4332863611 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -200,6 +200,7 @@ endif
config STMMAC_PCI
tristate "STMMAC PCI bus support"
depends on STMMAC_ETH && PCI
+ select DWXPCS
---help---
This selects the platform specific bus support for the stmmac driver.
This driver was tested on XLINX XC2V3000 FF1152AMT0221
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index dcb2e29a5717..d4e232223941 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -29,6 +29,7 @@ struct stmmac_resources {
int wol_irq;
int lpi_irq;
int irq;
+ int phy_conv_irq;
};
struct stmmac_tx_info {
@@ -203,6 +204,7 @@ struct stmmac_priv {
void __iomem *mmcaddr;
void __iomem *ptpaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ int phy_conv_irq;
#ifdef CONFIG_DEBUG_FS
struct dentry *dbgfs_dir;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 06ccd216ae90..43e3d3799581 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2726,11 +2726,23 @@ static int stmmac_open(struct net_device *dev)
}
}
+ /* Start phy converter after MDIO bus IRQ handling is up */
+ if (priv->plat->setup_phy_conv) {
+ ret = priv->plat->setup_phy_conv(priv->mii, priv->phy_conv_irq);
+ if (ret < 0) {
+ netdev_err(priv->dev,
+ "%s: ERROR: setup phy conv (error: %d)\n",
+ __func__, ret);
+ goto phy_conv_error;
+ }
+ }
+
stmmac_enable_all_queues(priv);
stmmac_start_all_queues(priv);
return 0;
+phy_conv_error:
lpiirq_error:
if (priv->wol_irq != dev->irq)
free_irq(priv->wol_irq, dev);
@@ -2760,6 +2772,7 @@ static int stmmac_release(struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
u32 chan;
+ int ret;
if (priv->eee_enabled)
del_timer_sync(&priv->eee_ctrl_timer);
@@ -2782,6 +2795,17 @@ static int stmmac_release(struct net_device *dev)
if (priv->lpi_irq > 0)
free_irq(priv->lpi_irq, dev);
+ /* Start phy converter after MDIO bus IRQ handling is up */
+ if (priv->plat->remove_phy_conv) {
+ ret = priv->plat->remove_phy_conv(priv->mii);
+ if (ret < 0) {
+ netdev_err(priv->dev,
+ "%s: ERROR: remove phy conv (error: %d)\n",
+ __func__, ret);
+ return 0;
+ }
+ }
+
/* Stop TX/RX DMA and clear the descriptors */
stmmac_stop_all_dma(priv);
@@ -4424,6 +4448,7 @@ int stmmac_dvr_probe(struct device *device,
priv->dev->irq = res->irq;
priv->wol_irq = res->wol_irq;
priv->lpi_irq = res->lpi_irq;
+ priv->phy_conv_irq = res->phy_conv_irq;
if (!IS_ERR_OR_NULL(res->mac))
memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 20906287b6d4..c3dfb0e9b025 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -10,9 +10,10 @@
*******************************************************************************/
#include <linux/clk-provider.h>
+#include <linux/phy.h>
#include <linux/pci.h>
#include <linux/dmi.h>
-
+#include <linux/dwxpcs.h>
#include "stmmac.h"
/*
@@ -109,6 +110,42 @@ static const struct stmmac_pci_info stmmac_pci_info = {
.setup = stmmac_default_data,
};
+static struct dwxpcs_platform_data intel_mgbe_pdata = {
+ .mode = DWXPCS_MODE_SGMII_AN,
+ .ext_phy_addr = 0x0,
+};
+
+static struct mdio_board_info intel_mgbe_bdinfo = {
+ .bus_id = "stmmac-1",
+ .modalias = "dwxpcs",
+ .mdio_addr = 0x16,
+ .platform_data = &intel_mgbe_pdata,
+};
+
+static int setup_intel_mgbe_phy_conv(struct mii_bus *bus, int irq)
+{
+ struct dwxpcs_platform_data *pdata = &intel_mgbe_pdata;
+
+ pdata->irq = irq;
+
+ return mdiobus_create_device(bus, &intel_mgbe_bdinfo);
+}
+
+static int remove_intel_mgbe_phy_conv(struct mii_bus *bus)
+{
+ struct mdio_board_info *bdinfo = &intel_mgbe_bdinfo;
+ struct mdio_device *mdiodev;
+
+ mdiodev = mdiobus_get_mdio_device(bus, bdinfo->mdio_addr);
+
+ if (!mdiodev)
+ return -1;
+
+ mdio_device_remove(mdiodev);
+
+ return 0;
+}
+
static int intel_mgbe_common_data(struct pci_dev *pdev,
struct plat_stmmacenet_data *plat)
{
@@ -197,6 +234,11 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
/* Set the maxmtu to a default of JUMBO_LEN */
plat->maxmtu = JUMBO_LEN;
+ if (plat->interface == PHY_INTERFACE_MODE_SGMII) {
+ plat->setup_phy_conv = setup_intel_mgbe_phy_conv;
+ plat->remove_phy_conv = remove_intel_mgbe_phy_conv;
+ }
+
return 0;
}
@@ -441,6 +483,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
res.addr = pcim_iomap_table(pdev)[i];
res.wol_irq = pdev->irq;
res.irq = pdev->irq;
+ res.phy_conv_irq = res.irq;
return stmmac_dvr_probe(&pdev->dev, plat, &res);
}
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 7ad7ae35cf88..9ffd0e9c21b1 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -12,6 +12,7 @@
#ifndef __STMMAC_PLATFORM_DATA
#define __STMMAC_PLATFORM_DATA
+#include <linux/phy.h>
#include <linux/platform_device.h>
#define MTL_MAX_RX_QUEUES 8
@@ -162,6 +163,8 @@ struct plat_stmmacenet_data {
int (*init)(struct platform_device *pdev, void *priv);
void (*exit)(struct platform_device *pdev, void *priv);
struct mac_device_info *(*setup)(void *priv);
+ int (*setup_phy_conv)(struct mii_bus *bus, int irq);
+ int (*remove_phy_conv)(struct mii_bus *bus);
void *bsp_priv;
struct clk *stmmac_clk;
struct clk *pclk;
--
2.17.0
^ permalink raw reply related
* [RFC net-next v1 3/5] net: phy: add private data to mdio_device
From: Ong Boon Leong @ 2019-08-28 17:33 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828173321.25334-1-boon.leong.ong@intel.com>
PHY converter device is represented as mdio_device and requires private
data. So, we add pointer for private data to mdio_device struct.
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
include/linux/mdio.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index e0ccd56a7ac0..fc7dfbe75006 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -40,6 +40,8 @@ struct mdio_device {
struct reset_control *reset_ctrl;
unsigned int reset_assert_delay;
unsigned int reset_deassert_delay;
+ /* Private data */
+ void *priv;
};
#define to_mdio_device(d) container_of(d, struct mdio_device, dev)
--
2.17.0
^ permalink raw reply related
* [RFC net-next v1 2/5] net: phy: introduce mdiobus_get_mdio_device
From: Ong Boon Leong @ 2019-08-28 17:33 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828173321.25334-1-boon.leong.ong@intel.com>
Add the function to get mdio_device based on the mdio addr.
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
drivers/net/phy/mdio_bus.c | 6 ++++++
include/linux/mdio.h | 1 +
2 files changed, 7 insertions(+)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 06658d9197a1..96ef94f87ff1 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -130,6 +130,12 @@ struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
}
EXPORT_SYMBOL(mdiobus_get_phy);
+struct mdio_device *mdiobus_get_mdio_device(struct mii_bus *bus, int addr)
+{
+ return bus->mdio_map[addr];
+}
+EXPORT_SYMBOL(mdiobus_get_mdio_device);
+
bool mdiobus_is_registered_device(struct mii_bus *bus, int addr)
{
return bus->mdio_map[addr];
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index e8242ad88c81..e0ccd56a7ac0 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -315,6 +315,7 @@ int mdiobus_register_device(struct mdio_device *mdiodev);
int mdiobus_unregister_device(struct mdio_device *mdiodev);
bool mdiobus_is_registered_device(struct mii_bus *bus, int addr);
struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr);
+struct mdio_device *mdiobus_get_mdio_device(struct mii_bus *bus, int addr);
/**
* mdio_module_driver() - Helper macro for registering mdio drivers
--
2.17.0
^ permalink raw reply related
* [RFC net-next v1 1/5] net: phy: make mdiobus_create_device() function callable from Eth driver
From: Ong Boon Leong @ 2019-08-28 17:33 UTC (permalink / raw)
To: davem, linux, mcoquelin.stm32, joabreu, f.fainelli, andrew
Cc: netdev, linux-kernel, peppe.cavallaro, alexandre.torgue,
weifeng.voon
In-Reply-To: <20190828173321.25334-1-boon.leong.ong@intel.com>
PHY converter and external PHY drivers depend on MDIO functions of Eth
driver and such MDIO read/write completion may fire IRQ. The ISR for MDIO
completion IRQ is done in the open() function of driver.
For PHY converter mdio driver that registers ISR event that uses MDIO
read/write function during its probe() function, the MDIO ISR should have
been performed a head of time before mdio driver probe() is called. It is
for reason as such, the mdio device creation and registration will need
to be callable from Eth driver open() function.
Why existing way to register mdio_device for PHY converter that is done
via mdiobus_register_board_info() is not feasible is the mdio device
creation and registration happens inside Eth driver probe() function,
specifically in mdiobus_setup_mdiodevfrom_board_info() that is called
by mdiobus_register().
Therefore, to fulfill the need mentioned above, we make mdiobus_create_
device() to be callable from Eth driver open().
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
---
drivers/net/phy/mdio_bus.c | 5 +++--
include/linux/phy.h | 7 +++++++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index bd04fe762056..06658d9197a1 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -338,8 +338,8 @@ static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,
*
* Returns 0 on success or < 0 on error.
*/
-static int mdiobus_create_device(struct mii_bus *bus,
- struct mdio_board_info *bi)
+int mdiobus_create_device(struct mii_bus *bus,
+ struct mdio_board_info *bi)
{
struct mdio_device *mdiodev;
int ret = 0;
@@ -359,6 +359,7 @@ static int mdiobus_create_device(struct mii_bus *bus,
return ret;
}
+EXPORT_SYMBOL(mdiobus_create_device);
/**
* __mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
diff --git a/include/linux/phy.h b/include/linux/phy.h
index d26779f1fb6b..4524db57fe0b 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1249,12 +1249,19 @@ struct mdio_board_info {
#if IS_ENABLED(CONFIG_MDIO_DEVICE)
int mdiobus_register_board_info(const struct mdio_board_info *info,
unsigned int n);
+int mdiobus_create_device(struct mii_bus *bus, struct mdio_board_info *bi);
#else
static inline int mdiobus_register_board_info(const struct mdio_board_info *i,
unsigned int n)
{
return 0;
}
+
+static inline int mdiobus_create_device(struct mii_bus *bus,
+ struct mdio_board_info *bi)
+{
+ return 0;
+}
#endif
--
2.17.0
^ permalink raw reply related
* Re: [PATCH v1 net-next] net: stmmac: Add support for MDIO interrupts
From: Florian Fainelli @ 2019-08-28 17:14 UTC (permalink / raw)
To: Voon, Weifeng, Andrew Lunn
Cc: David S. Miller, Maxime Coquelin, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, Jose Abreu, Giuseppe Cavallaro,
Alexandre Torgue, Ong, Boon Leong
In-Reply-To: <D6759987A7968C4889FDA6FA91D5CBC814759747@PGSMSX103.gar.corp.intel.com>
On 8/28/19 10:07 AM, Voon, Weifeng wrote:
>>>> DW EQoS v5.xx controllers added capability for interrupt generation
>>>> when MDIO interface is done (GMII Busy bit is cleared).
>>>> This patch adds support for this interrupt on supported HW to avoid
>>>> polling on GMII Busy bit.
>>>>
>>>> stmmac_mdio_read() & stmmac_mdio_write() will sleep until wake_up()
>>>> is called by the interrupt handler.
>>>
>>> Hi Voon
>>>
>>> I _think_ there are some order of operation issues here. The mdiobus
>>> is registered in the probe function. As soon as of_mdiobus_register()
>>> is called, the MDIO bus must work. At that point MDIO read/writes can
>>> start to happen.
>>>
>>> As far as i can see, the interrupt handler is only requested in
>>> stmmac_open(). So it seems like any MDIO operations after probe, but
>>> before open are going to fail?
>>
>> AFAIR, wait_event_timeout() will continue to busy loop and wait until
>> the timeout, but not return an error because the polled condition was
>> true, at least that is my recollection from having the same issue with
>> the bcmgenet driver before it was moved to connecting to the PHY in the
>> ndo_open() function.
>> --
>> Florian
>
> Florian is right as the poll condition is still true after the timeout.
> Hence, any mdio operation after probe and before ndo_open will still work.
> The only cons here is that attaching the PHY will takes a full length of
> timeout time for each mdio_read and mdio_write.
> So we should attach the phy only after the interrupt handler is requested?
From a power management/resource utilization perspective, it is better
to initialize as close as possible from the time where you are actually
going to use the hardware, therefore ndo_open().
This may not be convenient or possible given how widely use stmmac is,
and I do not know if parts of the Ethernet MAC require the PHY to supply
the clock, in which case, you may have some chicke and egg conditions if
the design does not allow for MDIO to work independently from the data
plane. Also, I would be worried about introducing bugs.
You could do a couple of things:
- continue to probe the device with interrupts disabled and add a
condition around the call to wait_event_timeout() to do a busy-loop
without going to the maximum defined timeout, if the interrupt line is
requested, use wait_event_timeout()
- request the interrupt during the probe function, but only
unmask/enable the MDIO interrupts for the probe to succeed and leave the
data path interrupts for a later enabling during ndo_open()
--
Florian
^ permalink raw reply
* Re: [RFC PATCH 1/1] phylink: Set speed to SPEED_UNKNOWN when there is no PHY connected
From: Russell King - ARM Linux admin @ 2019-08-28 17:14 UTC (permalink / raw)
To: Vladimir Oltean; +Cc: andrew, f.fainelli, asolokha, netdev
In-Reply-To: <20190828145802.3609-2-olteanv@gmail.com>
On Wed, Aug 28, 2019 at 05:58:02PM +0300, Vladimir Oltean wrote:
> phylink_ethtool_ksettings_get can be called while the interface may not
> even be up, which should not be a problem. But there are drivers (e.g.
> gianfar) which connect to the PHY in .ndo_open and disconnect in
> .ndo_close. While odd, to my knowledge this is again not illegal and
> there may be more that do the same. But PHYLINK for example has this
> check in phylink_ethtool_ksettings_get:
>
> if (pl->phydev) {
> phy_ethtool_ksettings_get(pl->phydev, kset);
> } else {
> kset->base.port = pl->link_port;
> }
>
> So it will not populate kset->base.speed if there is no PHY connected.
> The speed will be 0, by way of a previous memset. Not SPEED_UNKNOWN.
> It is arguable whether that is legal or not. include/uapi/linux/ethtool.h
> says:
>
> All values 0 to INT_MAX are legal.
>
> By that measure it may be. But it sure would make users of the
> __ethtool_get_link_ksettings API need make more complicated checks
> (against -1, against 0, 1, etc). So far the kernel community has been ok
> with just checking for SPEED_UNKNOWN.
>
> Take net/sched/sch_taprio.c for example. The check in
> taprio_set_picos_per_byte is currently not robust enough and will
> trigger this division by zero, due to PHYLINK not setting SPEED_UNKNOWN:
>
> if (!__ethtool_get_link_ksettings(dev, &ecmd) &&
> ecmd.base.speed != SPEED_UNKNOWN)
> picos_per_byte = div64_s64(NSEC_PER_SEC * 1000LL * 8,
> ecmd.base.speed * 1000 * 1000);
The ethtool API says:
* If it is enabled then they are read-only; if the link
* is up they represent the negotiated link mode; if the link is down,
* the speed is 0, %SPEED_UNKNOWN or the highest enabled speed and
* @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
So, it seems that taprio is not following the API... I'd suggest either
fixing taprio, or getting agreement to change the ethtool API.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
^ permalink raw reply
* Re: [PATCH net-next 03/15] net: sgi: ioc3-eth: remove checkpatch errors/warning
From: Joe Perches @ 2019-08-28 17:10 UTC (permalink / raw)
To: Thomas Bogendoerfer, Ralf Baechle, Paul Burton, James Hogan,
David S. Miller, linux-mips, linux-kernel, netdev
In-Reply-To: <20190828140315.17048-4-tbogendoerfer@suse.de>
On Wed, 2019-08-28 at 16:03 +0200, Thomas Bogendoerfer wrote:
> Before massaging the driver further fix oddities found by checkpatch like
> - wrong indention
> - comment formatting
> - use of printk instead or netdev_xxx/pr_xxx
trivial notes:
Please try to make the code better rather than merely
shutting up checkpatch.
> diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
[]
> @@ -209,8 +201,7 @@ static inline void nic_write_bit(u32 __iomem *mcr, int bit)
> nic_wait(mcr);
> }
>
> -/*
> - * Read a byte from an iButton device
> +/* Read a byte from an iButton device
> */
These comment styles would be simpler on a single line
/* Read a byte from an iButton device */
> static u32 nic_read_byte(u32 __iomem *mcr)
> {
> @@ -223,8 +214,7 @@ static u32 nic_read_byte(u32 __iomem *mcr)
> return result;
> }
>
> -/*
> - * Write a byte to an iButton device
> +/* Write a byte to an iButton device
> */
/* Write a byte to an iButton device */
etc...
[]
> @@ -323,16 +315,15 @@ static int nic_init(u32 __iomem *mcr)
> break;
> }
>
> - printk("Found %s NIC", type);
> + pr_info("Found %s NIC", type);
> if (type != unknown)
> - printk (" registration number %pM, CRC %02x", serial, crc);
> - printk(".\n");
> + pr_cont(" registration number %pM, CRC %02x", serial, crc);
> + pr_cont(".\n");
This code would be more sensible as
if (type != unknown)
pr_info("Found %s NIC registration number %pM, CRC %02x\n",
type, serial, crc);
else
pr_info("Found %s NIC\n", type);
Though I don't know if registration number is actually a MAC
address or something else. If it's just a 6 byte identifier
that uses colon separation it should probably use "%6phC"
instead of "%pM"
[]
> @@ -645,22 +636,21 @@ static inline void ioc3_tx(struct net_device *dev)
> static void ioc3_error(struct net_device *dev, u32 eisr)
> {
> struct ioc3_private *ip = netdev_priv(dev);
> - unsigned char *iface = dev->name;
>
> spin_lock(&ip->ioc3_lock);
>
> if (eisr & EISR_RXOFLO)
> - printk(KERN_ERR "%s: RX overflow.\n", iface);
> + netdev_err(dev, "RX overflow.\n");
> if (eisr & EISR_RXBUFOFLO)
> - printk(KERN_ERR "%s: RX buffer overflow.\n", iface);
> + netdev_err(dev, "RX buffer overflow.\n");
> if (eisr & EISR_RXMEMERR)
> - printk(KERN_ERR "%s: RX PCI error.\n", iface);
> + netdev_err(dev, "RX PCI error.\n");
> if (eisr & EISR_RXPARERR)
> - printk(KERN_ERR "%s: RX SSRAM parity error.\n", iface);
> + netdev_err(dev, "RX SSRAM parity error.\n");
> if (eisr & EISR_TXBUFUFLO)
> - printk(KERN_ERR "%s: TX buffer underflow.\n", iface);
> + netdev_err(dev, "TX buffer underflow.\n");
> if (eisr & EISR_TXMEMERR)
> - printk(KERN_ERR "%s: TX PCI error.\n", iface);
> + netdev_err(dev, "TX PCI error.\n");
All of these should probably be ratelimited() output.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox