From: Andrew Lunn <andrew@lunn.ch>
To: Pantelis Antoniou <pantelis.antoniou@konsulko.com>,
David Miller <davem@davemloft.net>
Cc: Lee Jones <lee.jones@linaro.org>,
Linus Walleij <linus.walleij@linaro.org>,
Alexandre Courbot <gnurou@gmail.com>,
Rob Herring <robh+dt@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Frank Rowand <frowand.list@gmail.com>,
Wolfram Sang <wsa@the-dreams.de>,
David Woodhouse <dwmw2@infradead.org>,
Brian Norris <computersforpeace@gmail.com>,
Florian Fainelli <f.fainelli@gmail.com>,
Wim Van Sebroeck <wim@iguana.be>, Peter Rosin <peda@axentia.se>,
Debjit Ghosh <dghosh@juniper.net>,
Georgi Vlaev <gvlaev@juniper.net>,
Guenter Roeck <linux@roeck-us.net>,
Maryam Seraj <mseraj@juniper.net>,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-gpio@vger.kernel.org, linux-i2c@vger.kernel.org,
linux-mtd@lists.infradead.org, linux-watchdog@vger.
Subject: Re: [PATCH 09/10] net: phy: Add MDIO driver for Juniper's SAM FPGA
Date: Fri, 7 Oct 2016 23:13:26 +0200 [thread overview]
Message-ID: <20161007211326.GB10197@lunn.ch> (raw)
In-Reply-To: <1475853518-22264-10-git-send-email-pantelis.antoniou@konsulko.com>
On Fri, Oct 07, 2016 at 06:18:37PM +0300, Pantelis Antoniou wrote:
> From: Georgi Vlaev <gvlaev@juniper.net>
>
> Add driver for the MDIO IP block present in Juniper's
> SAM FPGA.
>
> This driver supports only Clause 45 of the 802.3 spec.
>
> Note that due to the fact that there are no drivers for
> Broadcom/Avago retimers on 10/40Ge path that are controlled
> from the MDIO interface there is a method to have direct
> access to registers via a debugfs interface.
This seems to be the wrong solution. Why not write those drivers?
Controlling stuff from user space is generally frowned up. So i expect
DaveM will NACK this patch. Please remove all the debugfs stuff.
> +static int mdio_sam_stat_wait(struct mii_bus *bus, u32 wait_mask)
> +{
> + struct mdio_sam_data *data = bus->priv;
> + unsigned long timeout;
> + u32 stat;
> +
> + timeout = jiffies + msecs_to_jiffies(MDIO_RDY_TMO);
> + do {
> + stat = ioread32(data->base + MDIO_STATUS);
> + if (stat & wait_mask)
> + return 0;
> +
> + usleep_range(50, 100);
> + } while (time_before(jiffies, timeout));
> +
> + return -EBUSY;
I've recently had to fix a loop like this in another
driver. usleep_range(50, 100) can sleep for a lot longer. If it sleeps
for MDIO_RDY_TMO you exit out with -EBUSY after a single iteration,
which is not what you want. It is better to make a fixed number of
iterations rather than a timeout.
> +}
> +
> +static int mdio_sam_read(struct mii_bus *bus, int phy_id, int regnum)
> +{
> + struct mdio_sam_data *data = bus->priv;
> + u32 command, res;
> + int ret;
> +
> + /* mdiobus_read holds the bus->mdio_lock mutex */
> +
> + if (!(regnum & MII_ADDR_C45))
> + return -ENXIO;
> +
> + ret = mdio_sam_stat_wait(bus, STAT_REG_RDY);
> + if (ret < 0)
> + return ret;
> +
> + command = regnum & 0x1fffff; /* regnum = (dev_id << 16) | reg */
> + command |= ((phy_id & 0x1f) << 21);
> +
> + iowrite32(command, data->base + MDIO_CMD1);
> + ioread32(data->base + MDIO_CMD1);
> + iowrite32(CMD2_READ | CMD2_ENABLE, data->base + MDIO_CMD2);
> + ioread32(data->base + MDIO_CMD2);
Why do you need to read the values back? Hardware bug?
> + iowrite32(TBL_CMD_REG_GO, data->base + MDIO_TBL_CMD);
> + ioread32(data->base + MDIO_TBL_CMD);
Although not wrong, most drivers use writel().
> +
> + usleep_range(50, 100);
> +
> + ret = mdio_sam_stat_wait(bus, (STAT_REG_DONE | STAT_REG_ERR));
Do you really need a wait before calling mdio_sam_stat_wait()? Isn't
that what it is supposed to do, wait...
> + if (ret < 0)
> + return ret;
> +
> + res = ioread32(data->base + MDIO_RESULT);
> +
> + if (res & RES_ERROR || !(res & RES_SUCCESS))
> + return -EIO;
> +
> + return (res & 0xffff);
> +}
> +
> +static int mdio_sam_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
> +{
> + struct mdio_sam_data *data = bus->priv;
> + u32 command;
> + int ret;
> +
> + /* mdiobus_write holds the bus->mdio_lock mutex */
> +
> + if (!(regnum & MII_ADDR_C45))
> + return -ENXIO;
> +
> + ret = mdio_sam_stat_wait(bus, STAT_REG_RDY);
> + if (ret < 0)
> + return ret;
> +
> + command = regnum & 0x1fffff; /* regnum = (dev_id << 16) | reg */
> + command |= ((phy_id & 0x1f) << 21);
> +
> + iowrite32(command, data->base + MDIO_CMD1);
> + ioread32(data->base + MDIO_CMD1);
> + iowrite32(CMD2_ENABLE | val, data->base + MDIO_CMD2);
> + ioread32(data->base + MDIO_CMD2);
> + iowrite32(TBL_CMD_REG_GO, data->base + MDIO_TBL_CMD);
> + ioread32(data->base + MDIO_TBL_CMD);
> +
> + usleep_range(50, 100);
> +
> + ret = mdio_sam_stat_wait(bus, (STAT_REG_DONE | STAT_REG_ERR));
> + if (ret < 0)
> + return ret;
> +
> + return 0;
> +}
> +
> +static int mdio_sam_reset(struct mii_bus *bus)
> +{
> + struct mdio_sam_data *data = bus->priv;
> +
> + iowrite32(TBL_CMD_SOFT_RESET, data->base + MDIO_TBL_CMD);
> + ioread32(data->base + MDIO_TBL_CMD);
> + mdelay(10);
> + iowrite32(0, data->base + MDIO_TBL_CMD);
> + ioread32(data->base + MDIO_TBL_CMD);
> +
> + /* zero tables */
> + memset_io(data->base + MDIO_CMD1, 0, 0x1000);
> + memset_io(data->base + MDIO_PRI_CMD1, 0, 0x1000);
What tables?
> +
> + return 0;
> +}
> +
> +static int mdio_sam_of_register_bus(struct platform_device *pdev,
> + struct device_node *np, void __iomem *base)
> +{
> + struct mii_bus *bus;
> + struct mdio_sam_data *data;
> + u32 reg;
> + int ret;
> +
> + bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*data));
> + if (!bus)
> + return -ENOMEM;
> +
> + /* bus offset */
> + ret = of_property_read_u32(np, "reg", ®);
> + if (ret)
> + return -ENODEV;
> +
> + data = bus->priv;
> + data->base = base + reg;
> +
> + bus->parent = &pdev->dev;
> + bus->name = "mdio-sam";
> + bus->read = mdio_sam_read;
> + bus->write = mdio_sam_write;
> + bus->reset = mdio_sam_reset;
> + snprintf(bus->id, MII_BUS_ID_SIZE, "mdiosam-%x-%x", pdev->id, reg);
> +
> + ret = of_mdiobus_register(bus, np);
> + if (ret < 0)
> + return ret;
> +#ifdef CONFIG_DEBUG_FS
> + ret = mdio_sam_debugfs_init(bus);
> + if (ret < 0)
> + goto err_unregister;
> +#endif
> + ret = device_create_bin_file(&bus->dev, &bin_attr_raw_io);
> + if (ret)
> + goto err_debugfs;
> +
> + return 0;
> +
> +err_debugfs:
> +#ifdef CONFIG_DEBUG_FS
> + mdio_sam_debugfs_remove(bus);
> +#endif
> +err_unregister:
> + mdiobus_unregister(bus);
> +
> + return ret;
> +}
> +
> +static int mdio_sam_of_unregister_bus(struct device_node *np)
> +{
> + struct mii_bus *bus;
> +
> + bus = of_mdio_find_bus(np);
> + if (bus) {
> + device_remove_bin_file(&bus->dev, &bin_attr_raw_io);
> +#ifdef CONFIG_DEBUG_FS
> + mdio_sam_debugfs_remove(bus);
> +#endif
> + mdiobus_unregister(bus);
> + }
> + return 0;
> +}
> +
> +static int mdio_sam_probe(struct platform_device *pdev)
> +{
> + struct device_node *np;
> + struct resource *res;
> + void __iomem *base;
> + int ret;
> +
> + if (!pdev->dev.of_node)
> + return -ENODEV;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_nocache(&pdev->dev, res->start,
> + resource_size(res));
Why nocache?
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + for_each_available_child_of_node(pdev->dev.of_node, np) {
> + ret = mdio_sam_of_register_bus(pdev, np, base);
> + if (ret)
> + goto err;
> + }
This is odd. There does not seem to be any shared resources. So you
should really have one MDIO bus as one device in the device tree.
Andrew
> +
> + return 0;
> +err:
> + /* roll back everything */
> + for_each_available_child_of_node(pdev->dev.of_node, np)
> + mdio_sam_of_unregister_bus(np);
> +
> + return ret;
> +}
> +
> +static int mdio_sam_remove(struct platform_device *pdev)
> +{
> + struct device_node *np;
> +
> + for_each_available_child_of_node(pdev->dev.of_node, np)
> + mdio_sam_of_unregister_bus(np);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mdio_sam_of_match[] = {
> + { .compatible = "jnx,mdio-sam" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, mdio_sam_of_match);
> +
> +static struct platform_driver mdio_sam_driver = {
> + .probe = mdio_sam_probe,
> + .remove = mdio_sam_remove,
> + .driver = {
> + .name = "mdio-sam",
> + .owner = THIS_MODULE,
> + .of_match_table = mdio_sam_of_match,
> + },
> +};
> +
> +module_platform_driver(mdio_sam_driver);
> +
> +MODULE_ALIAS("platform:mdio-sam");
> +MODULE_AUTHOR("Georgi Vlaev <gvlaev@juniper.net>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Juniper Networks SAM MDIO bus driver");
> --
> 1.9.1
>
next prev parent reply other threads:[~2016-10-07 21:13 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-07 15:18 [PATCH 00/10] Introduce Juniper SAM FPGA driver Pantelis Antoniou
2016-10-07 15:18 ` [PATCH 01/10] mfd: Add Juniper SAM FPGA MFD driver Pantelis Antoniou
2016-10-07 15:18 ` [PATCH 04/10] i2c: i2c-sam: Add device tree bindings Pantelis Antoniou
2016-10-10 19:54 ` Rob Herring
2016-10-11 7:13 ` Peter Rosin
2016-10-07 15:18 ` [PATCH 05/10] gpio: Introduce SAM gpio driver Pantelis Antoniou
2016-10-20 23:06 ` Linus Walleij
2016-10-07 15:18 ` [PATCH 06/10] gpio: sam: Document bindings of SAM FPGA GPIO block Pantelis Antoniou
2016-10-10 20:03 ` Rob Herring
2016-10-17 19:01 ` Pantelis Antoniou
2016-10-07 15:18 ` [PATCH 07/10] mtd: Add SAM Flash driver Pantelis Antoniou
2016-10-07 15:18 ` [PATCH 08/10] mtd: flash-sam: Bindings for Juniper's SAM FPGA flash Pantelis Antoniou
[not found] ` <1475853518-22264-9-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2016-10-10 20:07 ` Rob Herring
2016-10-17 19:03 ` Pantelis Antoniou
2016-10-07 15:18 ` [PATCH 09/10] net: phy: Add MDIO driver for Juniper's SAM FPGA Pantelis Antoniou
2016-10-07 21:13 ` Andrew Lunn [this message]
2016-10-08 16:30 ` Georgi Vlaev
[not found] ` <1475853518-22264-1-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2016-10-07 15:18 ` [PATCH 02/10] mfd: sam: Add documentation for the " Pantelis Antoniou
2016-10-10 19:47 ` Rob Herring
2016-10-07 15:18 ` [PATCH 03/10] i2c: Juniper SAM I2C driver Pantelis Antoniou
2016-10-07 15:18 ` [PATCH 10/10] net: mdio-sam: Add device tree documentation for SAM MDIO Pantelis Antoniou
[not found] ` <1475853518-22264-11-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
2016-10-10 8:50 ` Florian Fainelli
2016-10-10 14:53 ` Peter Rosin
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=20161007211326.GB10197@lunn.ch \
--to=andrew@lunn.ch \
--cc=computersforpeace@gmail.com \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=dghosh@juniper.net \
--cc=dwmw2@infradead.org \
--cc=f.fainelli@gmail.com \
--cc=frowand.list@gmail.com \
--cc=gnurou@gmail.com \
--cc=gvlaev@juniper.net \
--cc=lee.jones@linaro.org \
--cc=linus.walleij@linaro.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=linux-watchdog@vger. \
--cc=linux@roeck-us.net \
--cc=mark.rutland@arm.com \
--cc=mseraj@juniper.net \
--cc=pantelis.antoniou@konsulko.com \
--cc=peda@axentia.se \
--cc=robh+dt@kernel.org \
--cc=wim@iguana.be \
--cc=wsa@the-dreams.de \
/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).