From: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
To: Moritz Fischer <mdf-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org,
mark.rutland-5wv7dgnIgG8@public.gmane.org,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
Subject: Re: [PATCH 2/2] net: ethernet: nixge: Add support for National Instruments XGE netdev
Date: Fri, 14 Jul 2017 00:36:36 +0200 [thread overview]
Message-ID: <20170713223636.GF3120@lunn.ch> (raw)
In-Reply-To: <1499980909-11702-2-git-send-email-mdf-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> +++ b/drivers/net/ethernet/ni/nixge.c
> @@ -0,0 +1,1246 @@
> +/*
> + * Copyright (c) 2016-2017, National Instruments Corp.
> + *
> + * Network Driver for Ettus Research XGE MAC
> + *
> + * This is largely based on the Xilinx AXI Ethernet Driver,
> + * and uses the same DMA engine in the FPGA
Hi Moritz
Is the DMA code the same as in the AXI driver? Should it be pulled out
into a library and shared?
> +struct nixge_priv {
> + struct net_device *ndev;
> + struct device *dev;
> +
> + /* Connection to PHY device */
> + struct phy_device *phy_dev;
> + phy_interface_t phy_interface;
> + /* protecting link parameters */
> + spinlock_t lock;
> + int link;
> + int speed;
> + int duplex;
All these seem to be pointless. They are set, but never used.
> +
> +static inline void nixge_dma_write_reg(struct nixge_priv *priv, off_t offset,
> + u32 val)
Please leave it up to the compile to inline.
> +static void __nixge_device_reset(struct nixge_priv *priv, off_t offset)
> +{
> + u32 timeout;
> + /* Reset Axi DMA. This would reset NIXGE Ethernet core as well.
> + * The reset process of Axi DMA takes a while to complete as all
> + * pending commands/transfers will be flushed or completed during
> + * this reset process.
> + */
> + nixge_dma_write_reg(priv, offset, XAXIDMA_CR_RESET_MASK);
> + timeout = DELAY_OF_ONE_MILLISEC;
> + while (nixge_dma_read_reg(priv, offset) & XAXIDMA_CR_RESET_MASK) {
> + udelay(1);
There is a link between the 1 and the value of DELAY_OF_ONE_MILLISEC.
It would be good to try to link these two together.
> + if (--timeout == 0) {
> + netdev_err(priv->ndev, "%s: DMA reset timeout!\n",
> + __func__);
> + break;
> + }
> + }
> +}
> +
> +static void nixge_handle_link_change(struct net_device *ndev)
> +{
> + struct nixge_priv *priv = netdev_priv(ndev);
> + struct phy_device *phydev = ndev->phydev;
> + unsigned long flags;
> + int status_change = 0;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> +
> + if (phydev->link != priv->link) {
> + if (!phydev->link) {
> + priv->speed = 0;
> + priv->duplex = -1;
> + }
> + priv->link = phydev->link;
> +
> + status_change = 1;
> + }
> +
> + spin_unlock_irqrestore(&priv->lock, flags);
> +
> + if (status_change) {
> + if (phydev->link) {
> + netif_carrier_on(ndev);
> + netdev_info(ndev, "link up (%d/%s)\n",
> + phydev->speed,
> + phydev->duplex == DUPLEX_FULL ?
> + "Full" : "Half");
> + } else {
> + netif_carrier_off(ndev);
> + netdev_info(ndev, "link down\n");
> + }
phy_print_status() should be used.
Also, the phylib will handle netif_carrier_off/on for you.
> +static int nixge_open(struct net_device *ndev)
> +{
> + struct nixge_priv *priv = netdev_priv(ndev);
> + int ret;
> +
> + nixge_device_reset(ndev);
> +
> + /* start netif carrier down */
> + netif_carrier_off(ndev);
> +
> + if (!ndev->phydev)
> + netdev_err(ndev, "no phy, phy_start() failed\n");
Not really correct. You don't call phy_start(). And phy_start() cannot
indicate a failure, it is a void function.
It would be a lot better to bail out if there is no phy. Probably
during probe.
> +static s32 __nixge_set_mac_address(struct net_device *ndev, const void *addr)
> +{
> + struct nixge_priv *priv = netdev_priv(ndev);
> +
> + if (addr)
> + memcpy(ndev->dev_addr, addr, ETH_ALEN);
> + if (!is_valid_ether_addr(ndev->dev_addr))
> + eth_random_addr(ndev->dev_addr);
Messy. I would change this. Make addr mandatory. If it is invalid,
return an error. That will make nixge_net_set_mac_address() do the
right thing. When called from nixge_probe() should verify what it gets
from the nvmem, and if it is invalid, pass a random MAC address.
> +
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MAC_LSB,
> + (ndev->dev_addr[2]) << 24 |
> + (ndev->dev_addr[3] << 16) |
> + (ndev->dev_addr[4] << 8) |
> + (ndev->dev_addr[5] << 0));
> +
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MAC_MSB,
> + (ndev->dev_addr[1] | (ndev->dev_addr[0] << 8)));
> +
> + return 0;
> +}
> +
> +static void nixge_ethtools_get_drvinfo(struct net_device *ndev,
> + struct ethtool_drvinfo *ed)
> +{
> + strlcpy(ed->driver, "nixge", sizeof(ed->driver));
> + strlcpy(ed->version, "1.00a", sizeof(ed->version));
Driver version is pretty pointless. What does 1.00a mean? Say it gets
backported into F26. Is it still 1.00a even though lots of things
around it have changed?
> +int nixge_mdio_read(struct mii_bus *bus, int phy_id, int reg)
> +{
> + struct nixge_priv *priv = bus->priv;
> + u32 status, tmp;
> + int err;
> + u16 device;
> +
> + if (reg & MII_ADDR_C45) {
> + device = (reg >> 16) & 0x1f;
> +
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_ADDR, reg & 0xffff);
> +
> + tmp = NIXGE_MDIO_CLAUSE45 | NIXGE_MDIO_OP(NIXGE_MDIO_OP_ADDRESS)
> + | NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
> +
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp);
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1);
> +
> + err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status,
> + !status, 10, 1000);
> + if (err) {
> + dev_err(priv->dev, "timeout setting address");
> + return -ETIMEDOUT;
Better to return err.
> + }
> +
> + tmp = NIXGE_MDIO_CLAUSE45 | NIXGE_MDIO_OP(NIXGE_MDIO_OP_READ) |
> + NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
> + } else {
> + device = reg & 0x1f;
> +
> + tmp = NIXGE_MDIO_CLAUSE22 | NIXGE_MDIO_OP(MDIO_C22_READ) |
> + NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
> + }
> +
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp);
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1);
> +
> + err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status,
> + !status, 10, 1000);
> + if (err) {
> + dev_err(priv->dev, "timeout setting read command");
> + return -ETIMEDOUT;
Again, return err.
> + }
> +
> + status = nixge_ctrl_read_reg(priv, NIXGE_REG_MDIO_DATA);
> +
> + dev_dbg(priv->dev, "%s: phy_id = %x reg = %x got %x\n", __func__,
> + phy_id, reg & 0xffff, status);
> +
> + return status;
> +}
> +
> +int nixge_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
> +{
> + struct nixge_priv *priv = bus->priv;
> + u32 status, tmp;
> + int err;
> + u16 device;
> +
> + /* FIXME: Currently don't do writes */
> + if (reg & MII_ADDR_C45)
> + return 0;
-EOPNOTSUPP would be better.
> +
> + device = reg & 0x1f;
> +
> + tmp = NIXGE_MDIO_CLAUSE22 | NIXGE_MDIO_OP(MDIO_C22_WRITE) |
> + NIXGE_MDIO_ADDR(phy_id) | NIXGE_MDIO_MMD(device);
> +
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_DATA, val);
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_OP, tmp);
> + nixge_ctrl_write_reg(priv, NIXGE_REG_MDIO_CTRL, 1);
> +
> + err = nixge_ctrl_poll_timeout(priv, NIXGE_REG_MDIO_CTRL, status,
> + !status, 10, 1000);
> + if (err) {
> + dev_err(priv->dev, "timeout setting write command");
> + return -ETIMEDOUT;
> + }
> +
> + dev_dbg(priv->dev, "%x %x <- %x\n", phy_id, reg, val);
> +
> + return 0;
> +}
> +
> +int nixge_mdio_setup(struct nixge_priv *priv, struct device_node *np)
> +{
> + struct mii_bus *bus;
> + struct resource res;
> + int err;
> +
> + bus = mdiobus_alloc();
> + if (!bus)
> + return -ENOMEM;
> +
> + of_address_to_resource(np, 0, &res);
> + snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
> + (unsigned long long)res.start);
There are more meaningful things you could use, e.g. dev_name(priv->dev)
> + bus->priv = priv;
> + bus->name = "NIXGE_MAC_mii_bus";
> + bus->read = nixge_mdio_read;
> + bus->write = nixge_mdio_write;
> + bus->parent = priv->dev;
> +
> + priv->mii_bus = bus;
> + err = of_mdiobus_register(bus, np);
> + if (err)
> + goto err_register;
> +
> + dev_info(priv->dev, "MDIO bus registered\n");
> +
> + return 0;
> +
> +err_register:
> + mdiobus_free(bus);
> + return err;
> +}
> +
> +static void *nixge_get_nvmem_address(struct device *dev)
> +{
> + struct nvmem_cell *cell;
> + size_t cell_size;
> + char *mac;
> +
> + cell = nvmem_cell_get(dev, "address");
> + if (IS_ERR(cell))
> + return cell;
> +
> + mac = nvmem_cell_read(cell, &cell_size);
> + nvmem_cell_put(cell);
> +
> + if (IS_ERR(mac))
> + return mac;
> +
> + return mac;
Pointless if()
> +}
> +
> +static int nixge_probe(struct platform_device *pdev)
> +{
> + int err;
> + struct nixge_priv *priv;
> + struct net_device *ndev;
> + struct resource *dmares;
> + const char *mac_addr;
> +
> + ndev = alloc_etherdev(sizeof(*priv));
> + if (!ndev)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, ndev);
> + SET_NETDEV_DEV(ndev, &pdev->dev);
> +
> + ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
> + ndev->features = NETIF_F_SG;
> + ndev->netdev_ops = &nixge_netdev_ops;
> + ndev->ethtool_ops = &nixge_ethtool_ops;
> +
> + /* MTU range: 64 - 9000 */
> + ndev->min_mtu = 64;
> + ndev->max_mtu = NIXGE_JUMBO_MTU;
> +
> + mac_addr = nixge_get_nvmem_address(&pdev->dev);
> + if (mac_addr)
> + ether_addr_copy(ndev->dev_addr, mac_addr);
> + else
> + eth_hw_addr_random(ndev);
> +
> + priv = netdev_priv(ndev);
> + priv->ndev = ndev;
> + priv->dev = &pdev->dev;
> +
> + priv->features = 0;
> + /* default to this for now ... */
> + priv->rxmem = 10000;
> +
> + dmares = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + priv->dma_regs = devm_ioremap_resource(&pdev->dev, dmares);
> + if (IS_ERR(priv->dma_regs)) {
> + dev_err(&pdev->dev, "failed to map dma regs\n");
> + return PTR_ERR(priv->dma_regs);
> + }
> + priv->ctrl_regs = priv->dma_regs + 0x4000;
> + __nixge_set_mac_address(ndev, mac_addr);
> +
> + priv->tx_irq = platform_get_irq_byname(pdev, "tx-irq");
> + if (priv->tx_irq < 0) {
> + dev_err(&pdev->dev, "no tx irq available");
> + return priv->tx_irq;
> + }
> +
> + priv->rx_irq = platform_get_irq_byname(pdev, "rx-irq");
> + if (priv->rx_irq < 0) {
> + dev_err(&pdev->dev, "no rx irq available");
> + return priv->rx_irq;
> + }
> +
> + priv->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
> + priv->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
> +
> + spin_lock_init(&priv->lock);
> +
> + err = nixge_mdio_setup(priv, pdev->dev.of_node);
> + if (err) {
> + dev_warn(&pdev->dev, "error registering mdio bus");
> + goto free_netdev;
> + }
> +
> + priv->phy_dev = phy_find_first(priv->mii_bus);
> + if (!priv->phy_dev) {
> + dev_err(&pdev->dev, "error finding a phy ...");
> + goto free_netdev;
> + }
I don't recommend this. Enforce the binding has a phy-handle.
> +
> + err = register_netdev(priv->ndev);
> + if (err) {
> + dev_err(priv->dev, "register_netdev() error (%i)\n", err);
> + goto free_netdev;
> + }
> +
> + err = phy_connect_direct(ndev, priv->phy_dev, &nixge_handle_link_change,
> + priv->phy_interface);
and here use of_phy_connect().
And where do you set phy_interface? You should be reading it from
device tree.
> + if (err) {
> + dev_err(&pdev->dev, "failed to attach to phy ...");
> + goto unregister_mdio;
> + }
> +
> + /* not sure if this is the correct way of dealing with this ... */
> + ndev->phydev->supported &= ~(SUPPORTED_Autoneg);
> + ndev->phydev->advertising = ndev->phydev->supported;
> + ndev->phydev->autoneg = AUTONEG_DISABLE;
What are you trying to achieve?
Andrew
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2017-07-13 22:36 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-13 21:21 [PATCH 1/2] dt-bindings: net: Add bindings for National Instruments XGE netdev Moritz Fischer
2017-07-13 21:21 ` [PATCH 2/2] net: ethernet: nixge: Add support " Moritz Fischer
2017-07-14 5:54 ` kbuild test robot
[not found] ` <1499980909-11702-2-git-send-email-mdf-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2017-07-13 22:36 ` Andrew Lunn [this message]
[not found] ` <20170713223636.GF3120-g2DYL2Zd6BY@public.gmane.org>
2017-07-14 0:31 ` Moritz Fischer
2017-07-14 1:34 ` Andrew Lunn
[not found] ` <20170714013435.GA9065-g2DYL2Zd6BY@public.gmane.org>
2017-07-14 3:36 ` Moritz Fischer
2017-07-15 14:36 ` kbuild test robot
2017-07-14 0:33 ` [PATCH 1/2] dt-bindings: net: Add bindings " YUAN Linyu
2017-07-14 0:36 ` Moritz Fischer
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=20170713223636.GF3120@lunn.ch \
--to=andrew-g2dyl2zd6by@public.gmane.org \
--cc=davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org \
--cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \
--cc=mdf-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.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).