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]
Message-Id: <1452602374.2567989.489760178.5DD04117@webmail.messagingengine.com>
Date:	Tue, 12 Jan 2016 12:39:34 +0000
From:	Graeme Gregory <gg@...mlogic.co.uk>
To:	Yankejian <yankejian@...wei.com> (Hackim Yim)
Cc:	rjw@...ysocki.net, lenb@...nel.org, davem@...emloft.net,
	liguozhu@...wei.com, yisen.zhuang@...wei.com,
	huangdaode@...ilicon.com, lipeng321@...wei.com,
	linux-kernel@...r.kernel.org, linux-acpi@...r.kernel.org,
	linuxarm@...wei.com
Subject: Re: [PATCH] ACPI: Add phylib support code for mdio



On Tue, 12 Jan 2016, at 12:12 PM, Yankejian (Hackim Yim) wrote:
> Hi Graeme,
> I some how missed to reply this. Sorry for this!
> 
> HNS needs to configure PHYs dynamically parameter. So HNS try to call
> Linux PHY driver to help access to PHYs. If PHYs access will be
> implemented in BIOS,
> it seems that HNS needs repeatedly communication with BIOS.
> And we have read other ethernet drivers with PHYs as well, like
> 1) APM X-Gene Ethernet Driver, and
> 2) AMD 10Gb Ethernet driver, and
> 3) Intel IXGBE.
> Both AMD and Intel try to implement PHYs access routines itself. The
> drivers
> needs to implement PHY access routines includes the popular PHYs.
> APM X-Gene Ethernet Driver needs Linux PHY driver help to access PHYs. It
> implements the new routines help to access Linux PHY driver, then access
> PHYs.
> As the drivers shows, each MDIO controller connects one PHY. Sometimes,
> one MDIO
> may control several PHYs, like HNS.
> 
> Firstly, let's go over the HNS hardware topology as below. The MDIO
> controller may
> control several PHYs, and each PHY connects to a MAC device.
>                        cpu                       
>                         |                        
>                         |                        
>      ------------------------------------------- 
>     |                   |                       |
>     |                   |                       |
>     |                  dsaf                     |
>     |                   |                       |
>     |      ---------------------------          |
>     |     |         |         |       |         |
>     |     |         |         |       |         |
>     |    MAC       MAC       MAC     MAC        |
>     |     |         |         |       |         |
>      ---- |-------- |-------- |       | --------|
>          ||        ||        ||       ||         
>          PHY       PHY       PHY     PHY         
> 
> As we know, Linux Mido bus can be registered by multi phy devices. Then
> net device
> can find mdio bus through phy node information. So
> 
>  MDIO_BUS0    NET-DEVECE0    NET-DEVICE1   ...   NET-DEVICEn    MDIO_BUS1
>     |                 |               |             |                |
>     |                 |               |             |                |
>     |                 |               |             |                |
>     |                 |               |             |    ------------
>      -----------------|------------   |             |   |
>                   |   |            |  |             |   |
>               PHY-DEVICE0    PHY-DEVICE1   ...   PHY-DEVICEn
> 
> 
> If we push this patch successfully, the other SOC with the same topology
> can use this
> common routines directly.
> Thanks again.
> 

Thanks for the detailed explanation, I see now why you wish to do this
dynamically.

Then I guess the job is to make sure that the PHY stuff is well defined
in _DSD. I know Redhat submitted a document.

Thanks

Graeme

> 
> 
> On 2015/12/3 18:47, Graeme Gregory wrote:
> > On Thu, Dec 03, 2015 at 09:54:43AM +0800, yankejian wrote:
> >> Add support for getting the PHY devices on an MDIO bus by ACPI.
> >> Currently many of the ethernet drivers are open coding a solution
> >> for reading data out of ACPI to find the correct PHY device.
> >> This patch implements a set of common routines are similar to of_mdio.c
> >>
> > The general conclusion for the ACPI on ARM64 discussion so far has been that
> > things like PHYs should be setup by the firmware before the kernel takes
> > control.
> >
> > I am unsure that this doing it the same way as DT with a different
> > description language is the way to go.
> >
> > Graeme
> >
> >> Signed-off-by: yankejian <yankejian@...wei.com>
> >> ---
> >>  drivers/acpi/Makefile     |   3 +
> >>  drivers/acpi/acpi_mdio.c  | 263 ++++++++++++++++++++++++++++++++++++++++++++++
> >>  include/linux/acpi_mdio.h |  68 ++++++++++++
> >>  3 files changed, 334 insertions(+)
> >>  create mode 100644 drivers/acpi/acpi_mdio.c
> >>  create mode 100644 include/linux/acpi_mdio.h
> >>
> >> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> >> index 675eaf3..832e7d6 100644
> >> --- a/drivers/acpi/Makefile
> >> +++ b/drivers/acpi/Makefile
> >> @@ -35,6 +35,7 @@ acpi-y				+= bus.o glue.o
> >>  acpi-y				+= scan.o
> >>  acpi-y				+= resource.o
> >>  acpi-y				+= acpi_processor.o
> >> +acpi-y				+= acpi_mdio.o
> >>  acpi-y				+= processor_core.o
> >>  acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
> >>  acpi-y				+= ec.o
> >> @@ -65,6 +66,7 @@ obj-$(CONFIG_ACPI_BUTTON)	+= button.o
> >>  obj-$(CONFIG_ACPI_FAN)		+= fan.o
> >>  obj-$(CONFIG_ACPI_VIDEO)	+= video.o
> >>  obj-$(CONFIG_ACPI_PCI_SLOT)	+= pci_slot.o
> >> +obj-$(CONFIG_PCI_MMCONFIG)	+= mcfg.o
> >>  obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
> >>  obj-y				+= container.o
> >>  obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
> >> @@ -79,6 +81,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
> >>  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
> >>  obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
> >>  obj-$(CONFIG_ACPI_CPPC_LIB)	+= cppc_acpi.o
> >> +obj-$(CONFIG_IORT_TABLE) 	+= iort.o
> >>  
> >>  # processor has its own "processor." module_param namespace
> >>  processor-y			:= processor_driver.o
> >> diff --git a/drivers/acpi/acpi_mdio.c b/drivers/acpi/acpi_mdio.c
> >> new file mode 100644
> >> index 0000000..3a5871d
> >> --- /dev/null
> >> +++ b/drivers/acpi/acpi_mdio.c
> >> @@ -0,0 +1,263 @@
> >> +/*
> >> + * Copyright (c) 2015 Hisilicon Limited.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#include <linux/acpi.h>
> >> +#include <linux/acpi_mdio.h>
> >> +#include <linux/device.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/module.h>
> >> +#include <linux/netdevice.h>
> >> +#include <linux/phy.h>
> >> +#include <linux/phy_fixed.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/spinlock_types.h>
> >> +
> >> +static
> >> +int acpi_mdiobus_register_phy(struct mii_bus *mdio, struct fwnode_handle *child,
> >> +			      u32 addr)
> >> +{
> >> +	struct phy_device *phy;
> >> +	const char *phy_type;
> >> +	bool is_c45;
> >> +	int rc;
> >> +
> >> +	rc = fwnode_property_read_string(child, "ethernet-phy", &phy_type);
> >> +	if (rc < 0)
> >> +		return rc;
> >> +
> >> +	if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c45",
> >> +		     sizeof("ethernet-phy-ieee802.3-c45")))
> >> +		is_c45 = 1;
> >> +	else if (!strncmp(phy_type, "ethernet-phy-ieee802.3-c22",
> >> +			  sizeof("ethernet-phy-ieee802.3-c22")))
> >> +		is_c45 = 0;
> >> +	else
> >> +		return -ENODATA;
> >> +
> >> +	phy = get_phy_device(mdio, addr, is_c45);
> >> +	if (!phy || IS_ERR(phy))
> >> +		return 1;
> >> +
> >> +	/* Associate the fw node with the device structure so it
> >> +	 * can be looked up later
> >> +	 */
> >> +	phy->dev.fwnode = child;
> >> +
> >> +	if (mdio->irq)
> >> +		phy->irq = mdio->irq[addr];
> >> +
> >> +	if (fwnode_property_read_bool(child, "broken-turn-around"))
> >> +		mdio->phy_ignore_ta_mask |= 1 << addr;
> >> +
> >> +	/* All data is now stored in the phy struct;
> >> +	 * register it
> >> +	 */
> >> +	rc = phy_device_register(phy);
> >> +	if (rc) {
> >> +		phy_device_free(phy);
> >> +		return 1;
> >> +	}
> >> +
> >> +	dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
> >> +{
> >> +	u32 addr;
> >> +	int ret;
> >> +
> >> +	ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
> >> +	if (ret < 0) {
> >> +		dev_err(dev, "has invalid PHY address ret:%d\n", ret);
> >> +		return ret;
> >> +	}
> >> +
> >> +	if (addr >= PHY_MAX_ADDR) {
> >> +		dev_err(dev, "PHY address %i is too large\n", addr);
> >> +		return -EINVAL;
> >> +	}
> >> +
> >> +	return addr;
> >> +}
> >> +EXPORT_SYMBOL(acpi_mdio_parse_addr);
> >> +
> >> +/**
> >> + * acpi_mdiobus_register - Register mii_bus and create PHYs
> >> + * @mdio: pointer to mii_bus structure
> >> + * @fwnode: pointer to framework node of MDIO bus.
> >> + *
> >> + * This function registers the mii_bus structure and registers a phy_device
> >> + * for each child node of mdio device.
> >> + */
> >> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode)
> >> +{
> >> +	struct fwnode_handle *child;
> >> +	struct acpi_device *adev;
> >> +	bool scanphys = false;
> >> +	int addr, rc, i;
> >> +
> >> +	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
> >> +	 * the framework node are populated after the bus has been registered
> >> +	 */
> >> +	mdio->phy_mask = ~0;
> >> +
> >> +	/* Clear all the IRQ properties */
> >> +	if (mdio->irq)
> >> +		for (i = 0; i < PHY_MAX_ADDR; i++)
> >> +			mdio->irq[i] = PHY_POLL;
> >> +
> >> +	mdio->dev.fwnode = fwnode;
> >> +
> >> +	/* Register the MDIO bus */
> >> +	rc = mdiobus_register(mdio);
> >> +	if (rc)
> >> +		return rc;
> >> +
> >> +	/* Loop over the child nodes and register a phy_device for each one */
> >> +	device_for_each_child_node(&mdio->dev, child) {
> >> +		adev = to_acpi_device_node(child);
> >> +		if (!adev)
> >> +			continue;
> >> +
> >> +		addr = acpi_mdio_parse_addr(&adev->dev, child);
> >> +		if (addr < 0) {
> >> +			scanphys = true;
> >> +			continue;
> >> +		}
> >> +
> >> +		rc = acpi_mdiobus_register_phy(mdio, child, addr);
> >> +		dev_dbg(&mdio->dev, "acpi reg phy rc:%#x addr:%#x\n", rc, addr);
> >> +		if (rc)
> >> +			continue;
> >> +	}
> >> +
> >> +	if (!scanphys)
> >> +		return 0;
> >> +
> >> +	/* auto scan for PHYs with empty reg property */
> >> +	device_for_each_child_node(&mdio->dev, child) {
> >> +		/* Skip PHYs with reg property set */
> >> +		if (!fwnode_property_present(child, "reg"))
> >> +			continue;
> >> +
> >> +		for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
> >> +			/* skip already registered PHYs */
> >> +			if (mdio->phy_map[addr])
> >> +				continue;
> >> +
> >> +			/* be noisy to encourage people to set reg property */
> >> +			dev_info(&mdio->dev, "scan phy %s at address %i\n",
> >> +				 acpi_dev_name(to_acpi_device_node(child)),
> >> +				 addr);
> >> +
> >> +			rc = acpi_mdiobus_register_phy(mdio, child, addr);
> >> +			if (rc)
> >> +				continue;
> >> +		}
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL(acpi_mdiobus_register);
> >> +
> >> +/* Helper function for acpi_phy_find_device */
> >> +static int acpi_phy_match(struct device *dev, void *phy_fwnode)
> >> +{
> >> +	return dev->fwnode == phy_fwnode;
> >> +}
> >> +
> >> +/**
> >> + * acpi_phy_find_device - Give a PHY node, find the phy_device
> >> + * @phy_fwnode: Pointer to the phy's framework node
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure.
> >> + */
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
> >> +{
> >> +	struct device *d;
> >> +
> >> +	if (!phy_fwnode)
> >> +		return NULL;
> >> +
> >> +	d = bus_find_device(&mdio_bus_type, NULL, phy_fwnode, acpi_phy_match);
> >> +
> >> +	return d ? to_phy_device(d) : NULL;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_find_device);
> >> +
> >> +/**
> >> + * acpi_phy_attach - Attach to a PHY without starting the state machine
> >> + * @dev: pointer to net_device claiming the phy
> >> + * @phy_fwnode: framework Node pointer for the PHY
> >> + * @flags: flags to pass to the PHY
> >> + * @iface: PHY data interface type
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure. The
> >> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
> >> + */
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface)
> >> +{
> >> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
> >> +	int ret;
> >> +
> >> +	if (!phy)
> >> +		return NULL;
> >> +
> >> +	ret = phy_attach_direct(dev, phy, flags, iface);
> >> +
> >> +	/* refcount is held by phy_attach_direct() on success */
> >> +	put_device(&phy->dev);
> >> +
> >> +	return ret ? NULL : phy;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_attach);
> >> +
> >> +/**
> >> + * acpi_phy_connect - Connect to the phy described
> >> + * @dev: pointer to net_device claiming the phy
> >> + * @phy_fwnode: Pointer to framework node for the PHY
> >> + * @hndlr: Link state callback for the network device
> >> + * @iface: PHY data interface type
> >> + *
> >> + * If successful, returns a pointer to the phy_device with the embedded
> >> + * struct device refcount incremented by one, or NULL on failure. The
> >> + * refcount must be dropped by calling phy_disconnect() or phy_detach().
> >> + */
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface)
> >> +{
> >> +	struct phy_device *phy = acpi_phy_find_device(phy_fwnode);
> >> +	int ret;
> >> +
> >> +	if (!phy)
> >> +		return NULL;
> >> +
> >> +	phy->dev_flags = flags;
> >> +
> >> +	ret = phy_connect_direct(dev, phy, hndlr, iface);
> >> +
> >> +	/* refcount is held by phy_connect_direct() on success */
> >> +	put_device(&phy->dev);
> >> +
> >> +	return ret ? NULL : phy;
> >> +}
> >> +EXPORT_SYMBOL(acpi_phy_connect);
> >> +
> >> +MODULE_LICENSE("GPL");
> >> +MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
> >> diff --git a/include/linux/acpi_mdio.h b/include/linux/acpi_mdio.h
> >> new file mode 100644
> >> index 0000000..82b5be5
> >> --- /dev/null
> >> +++ b/include/linux/acpi_mdio.h
> >> @@ -0,0 +1,68 @@
> >> +/*
> >> + * Copyright (c) 2015 Hisilicon Limited.
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#ifndef __LINUX_ACPI_MDIO_H
> >> +#define __LINUX_ACPI_MDIO_H
> >> +
> >> +#include <linux/phy.h>
> >> +
> >> +#ifdef CONFIG_ACPI
> >> +
> >> +int acpi_mdio_parse_addr(struct device *dev, struct fwnode_handle *fwnode);
> >> +int acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode);
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode);
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface);
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface);
> >> +
> >> +#else
> >> +static inline int acpi_mdio_parse_addr(struct device *dev,
> >> +				       struct fwnode_handle *fwnode)
> >> +{
> >> +	return -ENXIO;
> >> +}
> >> +
> >> +static inline int acpi_mdiobus_register(struct mii_bus *mdio,
> >> +					struct fwnode_handle *fwnode)
> >> +{
> >> +	return -ENXIO;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_find_device(struct fwnode_handle *phy_fwnode)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_attach(struct net_device *dev,
> >> +				   struct fwnode_handle *phy_fwnode, u32 flags,
> >> +				   phy_interface_t iface)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +static inline
> >> +struct phy_device *acpi_phy_connect(struct net_device *dev,
> >> +				    struct fwnode_handle *phy_fwnode,
> >> +				    void (*hndlr)(struct net_device *),
> >> +				    u32 flags,
> >> +				    phy_interface_t iface)
> >> +{
> >> +	return NULL;
> >> +}
> >> +
> >> +#endif
> >> +
> >> +#endif /* __LINUX_ACPI_MDIO_H */
> >> -- 
> >> 1.9.1
> >>
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> >> the body of a message to majordomo@...r.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > .
> >
> 
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ