From: Shawn Guo <shawn.guo@linaro.org>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 2/3] net: add higmacv300 Ethernet driver for HiSilicon platform
Date: Wed, 13 Feb 2019 19:46:34 +0800 [thread overview]
Message-ID: <20190213114632.GB4027@dragon> (raw)
In-Reply-To: <CANr=Z=aK-ufWL2buNhZQa3vrnpZON4m+aV+VC2RO2XPQRZ6n2A@mail.gmail.com>
Hi Joe,
Thanks for spending time to review the patch.
On Mon, Feb 04, 2019 at 11:48:40PM +0000, Joe Hershberger wrote:
> On Mon, Jan 28, 2019 at 3:16 AM Shawn Guo <shawn.guo@linaro.org> wrote:
> >
> > It adds the driver for HIGMACV300 Ethernet controller found on HiSilicon
> > SoCs like Hi3798CV200. It's based on a downstream U-Boot driver, but
> > quite a lot of code gets rewritten and cleaned up to adopt driver model
> > and PHY API.
> >
> > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > ---
> > drivers/net/Kconfig | 9 +
> > drivers/net/Makefile | 1 +
> > drivers/net/higmacv300.c | 592 +++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 602 insertions(+)
> > create mode 100644 drivers/net/higmacv300.c
<snip>
> > +#define MDIO_WRITE 1
> > +#define MDIO_READ 2
> > +#define MDIO_COMMAND(rw, addr, reg) (BIT_MDIO_BUSY | \
> > + (((rw) & 0x3) << 16) | \
> > + (((addr) & 0x1f) << 8) | \
> > + ((reg) & 0x1f))
> > +#define MDIO_WRITE_CMD(addr, reg) MDIO_COMMAND(MDIO_WRITE, addr, reg)
> > +#define MDIO_READ_CMD(addr, reg) MDIO_COMMAND(MDIO_READ, addr, reg)
>
> This is a strange construct... can you just inline this into the
> actual functions? I don't see the value in these macros that hide
> what's happening.
Yes, I can eliminate the macros with inline code. That's actually what
kernel driver does.
>
> > +
> > +enum higmac_queue {
> > + RX_FQ,
> > + RX_BQ,
> > + TX_BQ,
> > + TX_RQ,
> > +};
<snip>
> > +static int higmac_free_pkt(struct udevice *dev, uchar *packet, int length)
> > +{
> > + if (packet)
> > + free(packet);
>
> Why free them and reallocate them? Won't that just fragment memory?
Practically it will not fragment the memory, as all the buffers get
a fixed size and allocation/free always happens as a pair for given
network transaction. But I still think it's a good suggestion to get
all buffers allocated at initialization time, so that we do not need to
allocate/free buffers repeatedly.
> Also, you should be somehow telling the MAC that the buffer /
> descriptor is no longer in use here.
Sensible suggestion.
>
> > +
> > + return 0;
> > +}
> > +
> > +static int higmac_recv(struct udevice *dev, int flags, uchar **packetp)
> > +{
> > + struct higmac_priv *priv = dev_get_priv(dev);
> > + struct higmac_desc *fqd = priv->rxfq;
> > + struct higmac_desc *bqd = priv->rxbq;
> > + int fqw_pos, fqr_pos, bqw_pos, bqr_pos;
> > + int timeout = 100000;
> > + unsigned long addr;
> > + int len = 0;
> > + int space;
> > + int i;
> > +
> > + fqw_pos = DESC_CNT(readl(priv->base + RX_FQ_WR_ADDR));
> > + fqr_pos = DESC_CNT(readl(priv->base + RX_FQ_RD_ADDR));
> > +
> > + if (fqw_pos >= fqr_pos)
> > + space = RX_DESC_NUM - (fqw_pos - fqr_pos);
> > + else
> > + space = fqr_pos - fqw_pos;
> > +
> > + /* Leave one free to distinguish full filled from empty buffer */
> > + for (i = 0; i < space - 1; i++) {
> > + void *buf = memalign(ARCH_DMA_MINALIGN, MAC_MAX_FRAME_SIZE);
> > +
> > + if (!buf)
> > + break;
> > +
> > + fqd = priv->rxfq + fqw_pos;
> > + fqd->buf_addr = (unsigned long)buf;
> > + invalidate_dcache_range(fqd->buf_addr,
> > + fqd->buf_addr + MAC_MAX_FRAME_SIZE);
> > +
> > + fqd->descvid = DESC_VLD_FREE;
> > + fqd->buf_len = MAC_MAX_FRAME_SIZE - 1;
> > + flush_desc(fqd);
> > +
> > + if (++fqw_pos >= RX_DESC_NUM)
> > + fqw_pos = 0;
> > +
> > + writel(DESC_BYTE(fqw_pos), priv->base + RX_FQ_WR_ADDR);
> > + }
> > +
> > + bqr_pos = DESC_CNT(readl(priv->base + RX_BQ_RD_ADDR));
> > + bqd += bqr_pos;
> > + /* BQ is only ever written by GMAC */
> > + invalidate_desc(bqd);
> > +
> > + do {
> > + bqw_pos = DESC_CNT(readl(priv->base + RX_BQ_WR_ADDR));
> > + udelay(1);
> > + } while (--timeout && bqw_pos == bqr_pos);
> > +
> > + if (!timeout)
> > + return -ETIMEDOUT;
> > +
> > + if (++bqr_pos >= RX_DESC_NUM)
> > + bqr_pos = 0;
> > +
> > + len = bqd->data_len;
> > +
> > + /* CPU should not have touched this buffer since we added it to FQ */
> > + addr = bqd->buf_addr;
> > + invalidate_dcache_range(addr, addr + len);
> > + *packetp = (void *)addr;
> > +
> > + writel(DESC_BYTE(bqr_pos), priv->base + RX_BQ_RD_ADDR);
>
> Does this belong in free_pkt()?
Yeah, I guess that's what you mean by telling MAC the descriptors are
not longer used above.
> > +
> > + return len;
> > +}
<snip>
> > +static int higmac_start(struct udevice *dev)
> > +{
> > + struct higmac_priv *priv = dev_get_priv(dev);
> > + struct phy_device *phydev = priv->phydev;
> > + int ret;
> > +
> > + ret = phy_startup(phydev);
> > + if (ret)
> > + return ret;
> > +
> > + if (!phydev->link) {
> > + debug("%s: link down\n", phydev->dev->name);
> > + return -ENODEV;
> > + }
> > +
> > + ret = higmac_adjust_link(priv);
> > + if (ret)
> > + return ret;
> > +
> > + /* Enable port */
> > + writel(0xf, priv->base + DESC_WR_RD_ENA);
>
> What is 0xf? No magic numbers please.
Okay, will define it.
>
> > + writel(BIT_TX_EN | BIT_RX_EN, priv->base + PORT_EN);
> > +
> > + return 0;
> > +}
> > +
> > +static void higmac_stop(struct udevice *dev)
> > +{
> > + struct higmac_priv *priv = dev_get_priv(dev);
> > +
> > + /* Disable port */
> > + writel(0, priv->base + PORT_EN);
> > + writel(0, priv->base + DESC_WR_RD_ENA);
> > +}
> > +
> > +static const struct eth_ops higmac_ops = {
> > + .start = higmac_start,
> > + .send = higmac_send,
> > + .recv = higmac_recv,
> > + .free_pkt = higmac_free_pkt,
> > + .stop = higmac_stop,
> > + .write_hwaddr = higmac_write_hwaddr,
> > +};
> > +
> > +static int higmac_wait_mdio_ready(struct higmac_priv *priv)
> > +{
> > + int timeout = 1000;
> > +
> > + while (--timeout) {
> > + /* Wait until busy bit is cleared */
> > + if ((readl(priv->base + MDIO_SINGLE_CMD) & BIT_MDIO_BUSY) == 0)
> > + break;
> > + udelay(10);
> > + }
>
> It would be good if you retrofit to use wait_bit or its macros
> throughout this driver instead of hand-writing it.
I didn't know that before. Thanks for the pointer. Will do.
>
> > +
> > + return timeout ? 0 : -ETIMEDOUT;
> > +}
<snip>
> > +static int higmac_probe(struct udevice *dev)
> > +{
> > + struct higmac_priv *priv = dev_get_priv(dev);
> > + struct phy_device *phydev;
> > + struct mii_dev *bus;
> > + int ret;
> > +
> > + ret = higmac_hw_init(priv);
> > + if (ret)
> > + return ret;
> > +
> > + bus = mdio_alloc();
> > + if (!bus)
> > + return -ENOMEM;
> > +
> > + bus->read = higmac_mdio_read;
> > + bus->write = higmac_mdio_write;
> > + bus->priv = priv;
> > + priv->bus = bus;
> > +
> > + ret = mdio_register_seq(bus, dev->seq);
> > + if (ret)
> > + return ret;
> > +
> > + phydev = phy_connect(bus, priv->phyaddr, dev, priv->phyintf);
> > + if (!phydev)
> > + return -ENODEV;
> > +
> > + phydev->supported &= PHY_GBIT_FEATURES;
>
> I would expect either phydev->supported &= ~PHY_GBIT_FEATURES; or
> phydev->supported |= PHY_GBIT_FEATURES;
To be honest, this code was copied from other drivers. It's all over
the drivers under driver/net. The phydev->supported gets initialized as
phydev->drv->features, and we want to make sure feature bits are set on
both sides, no?
Shawn
>
> > + phydev->advertising = phydev->supported;
> > + priv->phydev = phydev;
> > +
> > + ret = phy_config(phydev);
> > + if (ret)
> > + return ret;
> > +
> > + return 0;
> > +}
next prev parent reply other threads:[~2019-02-13 11:46 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-28 9:13 [U-Boot] [PATCH 0/3] Add Ethernet support for Poplar board Shawn Guo
2019-01-28 9:13 ` [U-Boot] [PATCH 1/3] reset: add reset driver for HiSilicon platform Shawn Guo
2019-01-29 21:57 ` Igor Opaniuk
2019-01-28 9:13 ` [U-Boot] [PATCH 2/3] net: add higmacv300 Ethernet " Shawn Guo
2019-01-29 21:50 ` Igor Opaniuk
2019-01-31 10:17 ` Shawn Guo
2019-02-04 23:53 ` Joe Hershberger
2019-02-13 11:46 ` Shawn Guo [this message]
2019-02-09 0:13 ` [U-Boot] [U-Boot, " Tom Rini
2019-02-13 7:21 ` Shawn Guo
2019-01-28 9:13 ` [U-Boot] [PATCH 3/3] poplar: enable Ethernet driver support Shawn Guo
2019-01-29 21:52 ` Igor Opaniuk
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=20190213114632.GB4027@dragon \
--to=shawn.guo@linaro.org \
--cc=u-boot@lists.denx.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