lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 26 Mar 2020 07:57:27 +0000
From:   Andy Duan <fugang.duan@....com>
To:     Martin Fuzzey <martin.fuzzey@...wbird.group>,
        Rob Herring <robh+dt@...nel.org>,
        Shawn Guo <shawnguo@...nel.org>,
        "David S. Miller" <davem@...emloft.net>
CC:     "netdev@...r.kernel.org" <netdev@...r.kernel.org>,
        Fabio Estevam <festevam@...il.com>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        Sascha Hauer <s.hauer@...gutronix.de>,
        dl-linux-imx <linux-imx@....com>,
        "devicetree@...r.kernel.org" <devicetree@...r.kernel.org>,
        Andrew Lunn <andrew@...n.ch>
Subject: RE: [EXT] [PATCH v2 1/4] net: fec: set GPR bit on suspend by DT
 configuration.

From: Martin Fuzzey <martin.fuzzey@...wbird.group> Sent: Thursday, March 26, 2020 2:12 AM
> On some SoCs, such as the i.MX6, it is necessary to set a bit in the SoC level
> GPR register before suspending for wake on lan to work.
> 
> The fec platform callback sleep_mode_enable was intended to allow this but
> the platform implementation was NAK'd back in 2015 [1]
> 
> This means that, currently, wake on lan is broken on mainline for the i.MX6 at
> least.
> 
> So implement the required bit setting in the fec driver by itself by adding a
> new optional DT property indicating the GPR register and adding the offset
> and bit information to the driver.
> 
> [1]
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.s
> pinics.net%2Flists%2Fnetdev%2Fmsg310922.html&amp;data=02%7C01%7Cf
> ugang.duan%40nxp.com%7Ce3cf15de6619429eb23108d7d0e8036a%7C686e
> a1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637207567214747980&am
> p;sdata=jfJGqJg7b0u31qfUDr6nxJPeKgp%2FisoTQSOJ607v6KM%3D&amp;rese
> rved=0
> 
> Signed-off-by: Martin Fuzzey <martin.fuzzey@...wbird.group>
> Signed-off-by: Fugang Duan <fugang.duan@....com>

The version look much better.

> ---
>  drivers/net/ethernet/freescale/fec.h      |   7 ++
>  drivers/net/ethernet/freescale/fec_main.c | 149
> ++++++++++++++++++++++++------
>  2 files changed, 127 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fec.h
> b/drivers/net/ethernet/freescale/fec.h
> index f79e57f..d89568f 100644
> --- a/drivers/net/ethernet/freescale/fec.h
> +++ b/drivers/net/ethernet/freescale/fec.h
> @@ -488,6 +488,12 @@ struct fec_enet_priv_rx_q {
>         struct  sk_buff *rx_skbuff[RX_RING_SIZE];  };
> 
> +struct fec_stop_mode_gpr {
> +       struct regmap *gpr;
> +       u8 reg;
> +       u8 bit;
> +};
> +
>  /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
>   * tx_bd_base always point to the base of the buffer descriptors.  The
>   * cur_rx and cur_tx point to the currently available buffer.
> @@ -562,6 +568,7 @@ struct fec_enet_private {
>         int hwts_tx_en;
>         struct delayed_work time_keep;
>         struct regulator *reg_phy;
> +       struct fec_stop_mode_gpr stop_gpr;
> 
>         unsigned int tx_align;
>         unsigned int rx_align;
> diff --git a/drivers/net/ethernet/freescale/fec_main.c
> b/drivers/net/ethernet/freescale/fec_main.c
> index 23c5fef..69cab0b 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -62,6 +62,8 @@
>  #include <linux/if_vlan.h>
>  #include <linux/pinctrl/consumer.h>
>  #include <linux/prefetch.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
>  #include <soc/imx/cpuidle.h>
> 
>  #include <asm/cacheflush.h>
> @@ -84,6 +86,56 @@
>  #define FEC_ENET_OPD_V 0xFFF0
>  #define FEC_MDIO_PM_TIMEOUT  100 /* ms */
> 
> +struct fec_devinfo {
> +       u32 quirks;
> +       u8 stop_gpr_reg;
> +       u8 stop_gpr_bit;
> +};
> +
> +static const struct fec_devinfo fec_imx25_info = {
> +       .quirks = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR |
> +                 FEC_QUIRK_HAS_FRREG,
> +};
> +
> +static const struct fec_devinfo fec_imx27_info = {
> +       .quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG, };
> +
> +static const struct fec_devinfo fec_imx28_info = {
> +       .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
> +                 FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
> +                 FEC_QUIRK_HAS_FRREG,
> +};
> +
> +static const struct fec_devinfo fec_imx6q_info = {
> +       .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
> +                 FEC_QUIRK_HAS_BUFDESC_EX |
> FEC_QUIRK_HAS_CSUM |
> +                 FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
> +                 FEC_QUIRK_HAS_RACC,
> +       .stop_gpr_reg = 0x34,
> +       .stop_gpr_bit = 27,
> +};
> +
> +static const struct fec_devinfo fec_mvf600_info = {
> +       .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC, };
> +
> +static const struct fec_devinfo fec_imx6x_info = {
> +       .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
> +                 FEC_QUIRK_HAS_BUFDESC_EX |
> FEC_QUIRK_HAS_CSUM |
> +                 FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
> +                 FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE
> |
> +                 FEC_QUIRK_HAS_RACC |
> FEC_QUIRK_HAS_COALESCE, };
> +
> +static const struct fec_devinfo fec_imx6ul_info = {
> +       .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
> +                 FEC_QUIRK_HAS_BUFDESC_EX |
> FEC_QUIRK_HAS_CSUM |
> +                 FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 |
> +                 FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC
> |
> +                 FEC_QUIRK_HAS_COALESCE, };
> +
>  static struct platform_device_id fec_devtype[] = {
>         {
>                 /* keep it for coldfire */ @@ -91,39 +143,25 @@
>                 .driver_data = 0,
>         }, {
>                 .name = "imx25-fec",
> -               .driver_data = FEC_QUIRK_USE_GASKET |
> FEC_QUIRK_MIB_CLEAR |
> -                              FEC_QUIRK_HAS_FRREG,
> +               .driver_data = (kernel_ulong_t)&fec_imx25_info,
>         }, {
>                 .name = "imx27-fec",
> -               .driver_data = FEC_QUIRK_MIB_CLEAR |
> FEC_QUIRK_HAS_FRREG,
> +               .driver_data = (kernel_ulong_t)&fec_imx27_info,
>         }, {
>                 .name = "imx28-fec",
> -               .driver_data = FEC_QUIRK_ENET_MAC |
> FEC_QUIRK_SWAP_FRAME |
> -                               FEC_QUIRK_SINGLE_MDIO |
> FEC_QUIRK_HAS_RACC |
> -                               FEC_QUIRK_HAS_FRREG,
> +               .driver_data = (kernel_ulong_t)&fec_imx28_info,
>         }, {
>                 .name = "imx6q-fec",
> -               .driver_data = FEC_QUIRK_ENET_MAC |
> FEC_QUIRK_HAS_GBIT |
> -                               FEC_QUIRK_HAS_BUFDESC_EX |
> FEC_QUIRK_HAS_CSUM |
> -                               FEC_QUIRK_HAS_VLAN |
> FEC_QUIRK_ERR006358 |
> -                               FEC_QUIRK_HAS_RACC,
> +               .driver_data = (kernel_ulong_t)&fec_imx6q_info,
>         }, {
>                 .name = "mvf600-fec",
> -               .driver_data = FEC_QUIRK_ENET_MAC |
> FEC_QUIRK_HAS_RACC,
> +               .driver_data = (kernel_ulong_t)&fec_mvf600_info,
>         }, {
>                 .name = "imx6sx-fec",
> -               .driver_data = FEC_QUIRK_ENET_MAC |
> FEC_QUIRK_HAS_GBIT |
> -                               FEC_QUIRK_HAS_BUFDESC_EX |
> FEC_QUIRK_HAS_CSUM |
> -                               FEC_QUIRK_HAS_VLAN |
> FEC_QUIRK_HAS_AVB |
> -                               FEC_QUIRK_ERR007885 |
> FEC_QUIRK_BUG_CAPTURE |
> -                               FEC_QUIRK_HAS_RACC |
> FEC_QUIRK_HAS_COALESCE,
> +               .driver_data = (kernel_ulong_t)&fec_imx6x_info,
>         }, {
>                 .name = "imx6ul-fec",
> -               .driver_data = FEC_QUIRK_ENET_MAC |
> FEC_QUIRK_HAS_GBIT |
> -                               FEC_QUIRK_HAS_BUFDESC_EX |
> FEC_QUIRK_HAS_CSUM |
> -                               FEC_QUIRK_HAS_VLAN |
> FEC_QUIRK_ERR007885 |
> -                               FEC_QUIRK_BUG_CAPTURE |
> FEC_QUIRK_HAS_RACC |
> -                               FEC_QUIRK_HAS_COALESCE,
> +               .driver_data = (kernel_ulong_t)&fec_imx6ul_info,
>         }, {
>                 /* sentinel */
>         }
> @@ -1092,11 +1130,28 @@ static void fec_enet_reset_skb(struct
> net_device *ndev)
> 
>  }
> 
> +static void fec_enet_stop_mode(struct fec_enet_private *fep, bool
> +enabled) {
> +       struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
> +       struct fec_stop_mode_gpr *stop_gpr = &fep->stop_gpr;
> +
> +       if (stop_gpr->gpr) {
> +               if (enabled)
> +                       regmap_update_bits(stop_gpr->gpr,
> stop_gpr->reg,
> +                                          BIT(stop_gpr->bit),
> +                                          BIT(stop_gpr->bit));
> +               else
> +                       regmap_update_bits(stop_gpr->gpr,
> stop_gpr->reg,
> +                                          BIT(stop_gpr->bit), 0);
> +       } else if (pdata && pdata->sleep_mode_enable) {
> +               pdata->sleep_mode_enable(enabled);
> +       }
> +}
> +
>  static void
>  fec_stop(struct net_device *ndev)
>  {
>         struct fec_enet_private *fep = netdev_priv(ndev);
> -       struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
>         u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
>         u32 val;
> 
> @@ -1125,9 +1180,7 @@ static void fec_enet_reset_skb(struct net_device
> *ndev)
>                 val = readl(fep->hwp + FEC_ECNTRL);
>                 val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
>                 writel(val, fep->hwp + FEC_ECNTRL);
> -
> -               if (pdata && pdata->sleep_mode_enable)
> -                       pdata->sleep_mode_enable(true);
> +               fec_enet_stop_mode(fep, true);
>         }
>         writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
> 
> @@ -3397,6 +3450,37 @@ static int fec_enet_get_irq_cnt(struct
> platform_device *pdev)
>         return irq_cnt;
>  }
> 
> +static int fec_enet_init_stop_mode(struct fec_enet_private *fep,
> +                                  struct fec_devinfo *dev_info,
> +                                  struct device_node *np) {
> +       struct device_node *gpr_np;
> +       int ret;
> +
> +       if (!dev_info)
> +               return 0;
> +
> +       gpr_np = of_parse_phandle(np, "gpr", 0);
> +       if (!gpr_np)
> +               return 0;
> +
> +       fep->stop_gpr.gpr = syscon_node_to_regmap(gpr_np);
> +       if (IS_ERR(fep->stop_gpr.gpr)) {
> +               dev_err(&fep->pdev->dev, "could not find gpr regmap\n");
> +               ret = PTR_ERR(fep->stop_gpr.gpr);
> +               fep->stop_gpr.gpr = NULL;
> +               goto out;
> +       }
> +
> +       fep->stop_gpr.reg = dev_info->stop_gpr_reg;
> +       fep->stop_gpr.bit = dev_info->stop_gpr_bit;
> +
> +out:
> +       of_node_put(gpr_np);
> +
> +       return ret;
> +}
> +
>  static int
>  fec_probe(struct platform_device *pdev)  { @@ -3412,6 +3496,7 @@
> static int fec_enet_get_irq_cnt(struct platform_device *pdev)
>         int num_rx_qs;
>         char irq_name[8];
>         int irq_cnt;
> +       struct fec_devinfo *dev_info;
> 
>         fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
> 
> @@ -3429,7 +3514,9 @@ static int fec_enet_get_irq_cnt(struct
> platform_device *pdev)
>         of_id = of_match_device(fec_dt_ids, &pdev->dev);
>         if (of_id)
>                 pdev->id_entry = of_id->data;
> -       fep->quirks = pdev->id_entry->driver_data;
> +       dev_info = (struct fec_devinfo *)pdev->id_entry->driver_data;
> +       if (dev_info)
> +               fep->quirks = dev_info->quirks;
> 
>         fep->netdev = ndev;
>         fep->num_rx_queues = num_rx_qs;
> @@ -3463,6 +3550,10 @@ static int fec_enet_get_irq_cnt(struct
> platform_device *pdev)
>         if (of_get_property(np, "fsl,magic-packet", NULL))
>                 fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
> 
> +       ret = fec_enet_init_stop_mode(fep, dev_info, np);
> +       if (ret)
> +               goto failed_stop_mode;
> +
>         phy_node = of_parse_phandle(np, "phy-handle", 0);
>         if (!phy_node && of_phy_is_fixed_link(np)) {
>                 ret = of_phy_register_fixed_link(np); @@ -3631,6
> +3722,7 @@ static int fec_enet_get_irq_cnt(struct platform_device *pdev)
>         if (of_phy_is_fixed_link(np))
>                 of_phy_deregister_fixed_link(np);
>         of_node_put(phy_node);
> +failed_stop_mode:
>  failed_phy:
>         dev_id--;
>  failed_ioremap:
> @@ -3708,7 +3800,6 @@ static int __maybe_unused fec_resume(struct
> device *dev)  {
>         struct net_device *ndev = dev_get_drvdata(dev);
>         struct fec_enet_private *fep = netdev_priv(ndev);
> -       struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
>         int ret;
>         int val;
> 
> @@ -3726,8 +3817,8 @@ static int __maybe_unused fec_resume(struct
> device *dev)
>                         goto failed_clk;
>                 }
>                 if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
> -                       if (pdata && pdata->sleep_mode_enable)
> -                               pdata->sleep_mode_enable(false);
> +                       fec_enet_stop_mode(fep, false);
> +
>                         val = readl(fep->hwp + FEC_ECNTRL);
>                         val &= ~(FEC_ECR_MAGICEN |
> FEC_ECR_SLEEP);
>                         writel(val, fep->hwp + FEC_ECNTRL);
> --
> 1.9.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ