netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Florian Fainelli <f.fainelli@gmail.com>
To: Matthew Garrett <matthew.garrett@nebula.com>
Cc: netdev <netdev@vger.kernel.org>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Kishon Vijay Abraham I <kishon@ti.com>
Subject: Re: [PATCH V3] net/dt: Add support for overriding phy configuration from device tree
Date: Tue, 4 Feb 2014 12:39:41 -0800	[thread overview]
Message-ID: <CAGVrzcZ4TFd=9KP+aoG47QbmqDJ1i23WBcEWDbzNRUfGmPvZHQ@mail.gmail.com> (raw)
In-Reply-To: <1389999459-9483-1-git-send-email-matthew.garrett@nebula.com>

2014-01-17 Matthew Garrett <matthew.garrett@nebula.com>:
> Some hardware may be broken in interesting and board-specific ways, such
> that various bits of functionality don't work. This patch provides a
> mechanism for overriding mii registers during init based on the contents of
> the device tree data, allowing board-specific fixups without having to
> pollute generic code.

It would be good to explain exactly how your hardware is broken
exactly. I really do not think that such a fine-grained setting where
you could disable, e.g: 100BaseT_Full, but allow 100BaseT_Half to
remain usable makes that much sense. In general, Gigabit might be
badly broken, but 100 and 10Mbits/sec should work fine. How about the
MASTER-SLAVE bit, is overriding it really required?

Is not a PHY fixup registered for a specific OUI the solution you are
looking for? I am also concerned that this creates PHY troubleshooting
issues much harder to debug than before as we may have no idea about
how much information has been put in Device Tree to override that.

Finally, how about making this more general just like the BCM87xx PHY
driver, which is supplied value/reg pairs directly? There are 16
common MII registers, and 16 others for vendor specific registers,
this is just covering for about 2% of the possible changes.

>
> Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
> ---
>
> V3: Break the main function out into some helper functions and store the
> values in some structs.
>
>  Documentation/devicetree/bindings/net/phy.txt | 21 +++++++
>  drivers/net/phy/phy_device.c                  | 29 ++++++++-
>  drivers/of/of_net.c                           | 87 +++++++++++++++++++++++++++
>  include/linux/of_net.h                        | 12 ++++
>  4 files changed, 148 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt
> index 7cd18fb..fc50f02 100644
> --- a/Documentation/devicetree/bindings/net/phy.txt
> +++ b/Documentation/devicetree/bindings/net/phy.txt
> @@ -23,6 +23,21 @@ Optional Properties:
>    assume clause 22. The compatible list may also contain other
>    elements.
>
> +The following properties may be added to either the phy node or the parent
> +ethernet device. If not present, the hardware defaults will be used.
> +
> +- phy-mii-advertise-10half: 1 to advertise half-duplex 10MBit, 0 to disable
> +- phy-mii-advertise-10full: 1 to advertise full-duplex 10MBit, 0 to disable
> +- phy-mii-advertise-100half: 1 to advertise half-duplex 100MBit, 0 to disable
> +- phy-mii-advertise-100full: 1 to advertise full-duplex 100MBit, 0 to disable
> +- phy-mii-advertise-100base4: 1 to advertise 100base4, 0 to disable
> +- phy-mii-advertise-1000half: 1 to advertise half-duplex 1000MBit, 0 to disable
> +- phy-mii-advertise-1000full: 1 to advertise full-duplex 1000MBit, 0 to disable
> +- phy-mii-manual-master: 1 to enable manual master/slave configuration, 0
> +  to disable manual master/slave configuration
> +- phy-mii-as-master: 1 to configure phy to act as master, 0 to configure phy
> +  to act as slave. Ignored if manual master/slave configuration is not enabled.
> +
>  Example:
>
>  ethernet-phy@0 {
> @@ -32,4 +47,10 @@ ethernet-phy@0 {
>         interrupts = <35 1>;
>         reg = <0>;
>         device_type = "ethernet-phy";
> +       // Disable advertising of full duplex 1000MBit
> +       phy-mii-advertise-1000full = <0>;
> +       // Force manual phy master/slave configuration
> +       phy-mii-manual-master = <1>;
> +       // Forcibly configure phy as slave
> +       phy-mii-as-master = <0>;
>  };
> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
> index d6447b3..91793bc 100644
> --- a/drivers/net/phy/phy_device.c
> +++ b/drivers/net/phy/phy_device.c
> @@ -33,6 +33,7 @@
>  #include <linux/mii.h>
>  #include <linux/ethtool.h>
>  #include <linux/phy.h>
> +#include <linux/of_net.h>
>
>  #include <asm/io.h>
>  #include <asm/irq.h>
> @@ -497,6 +498,28 @@ void phy_disconnect(struct phy_device *phydev)
>  }
>  EXPORT_SYMBOL(phy_disconnect);
>
> +int phy_override_from_of(struct phy_device *phydev)
> +{
> +       int reg, regval;
> +       u16 val, mask;
> +
> +       /* Check for phy register overrides from OF */
> +       for (reg = 0; reg < 16; reg++) {
> +               if (!of_get_mii_register(phydev, reg, &val, &mask)) {
> +                       if (!mask)
> +                               continue;
> +                       regval = phy_read(phydev, reg);
> +                       if (regval < 0)
> +                               continue;
> +                       regval &= ~mask;
> +                       regval |= val;
> +                       phy_write(phydev, reg, regval);
> +               }
> +       }
> +
> +       return 0;
> +}
> +
>  int phy_init_hw(struct phy_device *phydev)
>  {
>         int ret;
> @@ -508,7 +531,11 @@ int phy_init_hw(struct phy_device *phydev)
>         if (ret < 0)
>                 return ret;
>
> -       return phydev->drv->config_init(phydev);
> +       ret = phydev->drv->config_init(phydev);
> +       if (ret < 0)
> +               return ret;
> +
> +       return phy_override_from_of(phydev);
>  }
>
>  /**
> diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
> index 8f9be2e..75751b7 100644
> --- a/drivers/of/of_net.c
> +++ b/drivers/of/of_net.c
> @@ -93,3 +93,90 @@ const void *of_get_mac_address(struct device_node *np)
>         return NULL;
>  }
>  EXPORT_SYMBOL(of_get_mac_address);
> +
> +struct mii_override {
> +       char *prop;
> +       u32 supported;
> +       u16 value;
> +};
> +
> +static struct mii_override mii_advertise_override[] = {
> +       { "phy-mii-advertise-10half", SUPPORTED_10baseT_Half,
> +         ADVERTISE_10HALF },
> +       { "phy-mii-advertise-10full", SUPPORTED_10baseT_Full,
> +         ADVERTISE_10FULL },
> +       { "phy-mii-advertise-100half", SUPPORTED_100baseT_Half,
> +         ADVERTISE_100HALF },
> +       { "phy-mii-advertise-100full", SUPPORTED_100baseT_Full,
> +         ADVERTISE_100FULL },
> +       { "phy-mii-advertise-100base4", 0, ADVERTISE_100BASE4 },
> +       { NULL },
> +};
> +
> +static struct mii_override mii_gigabit_override[] = {
> +       { "phy-mii-advertise-1000half", SUPPORTED_1000baseT_Half,
> +         ADVERTISE_1000HALF },
> +       { "phy-mii-advertise-1000full", SUPPORTED_1000baseT_Full,
> +         ADVERTISE_1000FULL },
> +       { "phy-mii-as-master", 0, CTL1000_AS_MASTER },
> +       { "phy-mii-manual-master", 0, CTL1000_ENABLE_MASTER },
> +       { NULL },
> +};
> +
> +static void mii_handle_override(struct mii_override *override_list,
> +                               struct phy_device *phydev, u16 *val, u16 *mask)
> +{
> +       struct device *dev = &phydev->dev;
> +       struct device_node *np = dev->of_node;
> +       struct mii_override *override;
> +       u32 tmp;
> +
> +       if (!np && dev->parent->of_node)
> +               np = dev->parent->of_node;
> +
> +       if (!np)
> +               return;
> +
> +       for (override = &override_list[0]; override->prop != NULL; override++) {
> +               if (!of_property_read_u32(np, override->prop, &tmp)) {
> +                       if (tmp) {
> +                               *val |= override->value;
> +                               phydev->advertising |= override->supported;
> +                       } else {
> +                               phydev->advertising &= ~(override->supported);
> +                       }
> +
> +                       *mask |= override->value;
> +               }
> +       }
> +
> +       return;
> +}
> +
> +/**
> + * Provide phy register overrides from the device tree. Some hardware may
> + * be broken in interesting and board-specific ways, so we want a mechanism
> + * for the board data to provide overrides for default values. This should be
> + * called during phy init.
> + */
> +int of_get_mii_register(struct phy_device *phydev, int reg, u16 *val,
> +                       u16 *mask)
> +{
> +       *val = 0;
> +       *mask = 0;
> +
> +       switch (reg) {
> +       case MII_ADVERTISE:
> +               mii_handle_override(mii_advertise_override, phydev, val, mask);
> +               break;
> +
> +       case MII_CTRL1000:
> +               mii_handle_override(mii_gigabit_override, phydev, val, mask);
> +               break;
> +
> +       default:
> +               return -EINVAL;
> +       }
> +       return 0;
> +}
> +EXPORT_SYMBOL(of_get_mii_register);
> diff --git a/include/linux/of_net.h b/include/linux/of_net.h
> index 34597c8..2e478bc 100644
> --- a/include/linux/of_net.h
> +++ b/include/linux/of_net.h
> @@ -7,10 +7,14 @@
>  #ifndef __LINUX_OF_NET_H
>  #define __LINUX_OF_NET_H
>
> +#include <linux/phy.h>
> +
>  #ifdef CONFIG_OF_NET
>  #include <linux/of.h>
>  extern int of_get_phy_mode(struct device_node *np);
>  extern const void *of_get_mac_address(struct device_node *np);
> +extern int of_get_mii_register(struct phy_device *np, int reg, u16 *val,
> +                              u16 *mask);
>  #else
>  static inline int of_get_phy_mode(struct device_node *np)
>  {
> @@ -21,6 +25,14 @@ static inline const void *of_get_mac_address(struct device_node *np)
>  {
>         return NULL;
>  }
> +static inline int of_get_mii_register(struct phy_device *np, int reg, u16 *val,
> +                                     u16 *mask)
> +{
> +       *val = 0;
> +       *mask = 0;
> +
> +       return -EINVAL;
> +}
>  #endif
>
>  #endif /* __LINUX_OF_NET_H */
> --
> 1.8.4.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/



-- 
Florian

  parent reply	other threads:[~2014-02-04 20:39 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-01-15 21:38 [PATCH] net/dt: Add support for overriding phy configuration from device tree Matthew Garrett
2014-01-16 13:59 ` Gerhard Sittig
2014-01-16 14:40   ` Matthew Garrett
     [not found]   ` <20140116135905.GV20094-kDjWylLy9wD0K7fsECOQyeGNnDKD8DIp@public.gmane.org>
2014-01-16 14:47     ` [PATCH V2] " Matthew Garrett
     [not found]       ` <1389883631-1480-1-git-send-email-matthew.garrett-05XSO3Yj/JvQT0dZR+AlfA@public.gmane.org>
2014-01-16 15:16         ` Arnd Bergmann
     [not found]           ` < 1389999459-9483-1-git-send-email-matthew.garrett@nebula.com>
2014-01-17 22:57           ` [PATCH V3] " Matthew Garrett
2014-01-19 15:34             ` Ben Hutchings
     [not found]               ` <1390145654.16433.102.camel-nDn/Rdv9kqW9Jme8/bJn5UCKIB8iOfG2tUK59QYPAWc@public.gmane.org>
2014-02-04 19:01                 ` Florian Fainelli
2014-02-04 17:15             ` Grant Likely
2014-02-04 20:39             ` Florian Fainelli [this message]
2014-02-04 21:40               ` Ben Hutchings
2014-02-04 22:48                 ` Florian Fainelli
2014-02-05  9:47               ` Grant Likely
2014-02-05  9:51               ` David Laight
     [not found]                 ` <063D6719AE5E284EB5DD2968C1650D6D0F6B8BCA-VkEWCZq2GCInGFn1LkZF6NBPR1lH4CV8@public.gmane.org>
2014-02-07 22:43                   ` Florian Fainelli
2014-02-10 16:14               ` Gerlando Falauto
     [not found]                 ` <52F8FB03.6040606-SkAbAL50j+5BDgjK7y7TUQ@public.gmane.org>
2014-02-10 17:09                   ` Florian Fainelli
2014-02-11  9:09                     ` Gerlando Falauto
     [not found]                       ` <52F9E8E6.1090006-SkAbAL50j+5BDgjK7y7TUQ@public.gmane.org>
2014-02-11 17:43                         ` Florian Fainelli
2014-02-12  8:57                           ` Gerlando Falauto
2014-07-10 12:37             ` Gerlando Falauto
     [not found]               ` <53BE8912.4090804-SkAbAL50j+5BDgjK7y7TUQ@public.gmane.org>
2014-07-22 23:40                 ` Florian Fainelli

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAGVrzcZ4TFd=9KP+aoG47QbmqDJ1i23WBcEWDbzNRUfGmPvZHQ@mail.gmail.com' \
    --to=f.fainelli@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=kishon@ti.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=matthew.garrett@nebula.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).