From patchwork Sun Jun 5 17:57:36 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Fainelli X-Patchwork-Id: 850132 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter2.kernel.org (8.14.4/8.14.3) with ESMTP id p55I35OR026723 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Sun, 5 Jun 2011 18:03:26 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QTHa9-0006eV-9u; Sun, 05 Jun 2011 17:57:49 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QTHa9-00016r-0u; Sun, 05 Jun 2011 17:57:49 +0000 Received: from mail-ww0-f49.google.com ([74.125.82.49]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QTHa4-00016G-I8 for linux-arm-kernel@lists.infradead.org; Sun, 05 Jun 2011 17:57:46 +0000 Received: by wwb39 with SMTP id 39so2446086wwb.18 for ; Sun, 05 Jun 2011 10:57:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:subject:date:user-agent :organization:mime-version:content-type:content-transfer-encoding :message-id; bh=VfwS9f0g4ZfFYHTCIUby02600BNrFENBnlCJk9leW60=; b=HMWsoPKEd8yGNvQuba/h0/s1CrlKw44q5Cue06SvnmFe/uAyJFJLdrEocV4tNs9MiP vbjZ7r0acy1DyxPZAF2jGJrt8KoWwSmgK+SD1RgE7T2rTSwV6m7Ba6Nfnczy2LGK+oDT ejfDM0t2iVyH35ud6O53JRv514Pl5a0hwAPGY= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:subject:date:user-agent:organization:mime-version :content-type:content-transfer-encoding:message-id; b=B2EfjH2dwjmKsqvY8SUt9KMAJ6J+T58sk6BPkU9PRXJG9oA3zWqcT8ZKXQOKg3Za4E nr7Wmf5SMXLQw+vMV6ZtZQChRwHkPb0TnnlCVCCIXpskaHRadnKr4luyhVs4zoUBMY2A s8AZtkUePWELcj0Elp8+t2qmUJwIe7ZPLxUXk= Received: by 10.227.37.12 with SMTP id v12mr4168869wbd.20.1307296659167; Sun, 05 Jun 2011 10:57:39 -0700 (PDT) Received: from bender.localnet (fbx.mimichou.net [82.236.225.16]) by mx.google.com with ESMTPS id p21sm2343620wbh.57.2011.06.05.10.57.37 (version=SSLv3 cipher=OTHER); Sun, 05 Jun 2011 10:57:38 -0700 (PDT) From: Florian Fainelli To: netdev@vger.kernel.org, Lennert Buytenhek , Mika Westerberg , hsweeten@visionengravers.com, ryan@bluewatersys.com, linux-arm-kernel@lists.infradead.org, davem@davemloft.net Subject: [PATCH] ep93xx-eth: convert to phylib Date: Sun, 5 Jun 2011 19:57:36 +0200 User-Agent: KMail/1.13.6 (Linux/2.6.38-9-generic; KDE/4.6.2; x86_64; ; ) Organization: OpenWrt MIME-Version: 1.0 Message-Id: <201106051957.36492.florian@openwrt.org> X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110605_135745_001442_B6F4865A X-CRM114-Status: GOOD ( 22.52 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is freemail (f.fainelli[at]gmail.com) -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [74.125.82.49 listed in list.dnswl.org] 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.0 RFC_ABUSE_POST Both abuse and postmaster missing on sender domain X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Sun, 05 Jun 2011 18:03:26 +0000 (UTC) ep93xx-eth lacked support for monitoring link status changes, with this patch, link changes are now watched and reported correctly. Signed-off-by: Florian Fainelli diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig index 39e1c0d..53d075e 100644 --- a/drivers/net/arm/Kconfig +++ b/drivers/net/arm/Kconfig @@ -51,7 +51,7 @@ config ARM_KS8695_ETHER config EP93XX_ETH tristate "EP93xx Ethernet support" depends on ARM && ARCH_EP93XX - select MII + select PHYLIB help This is a driver for the ethernet hardware included in EP93xx CPUs. Say Y if you are building a kernel for EP93xx based devices. diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 5a77001..4669b6c 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -175,7 +176,11 @@ struct ep93xx_priv struct net_device *dev; struct napi_struct napi; - struct mii_if_info mii; + struct mii_bus *mii_bus; + struct phy_device *phydev; + int old_link; + int old_duplex; + unsigned int phy_addr; u8 mdc_divisor; }; @@ -186,8 +191,9 @@ struct ep93xx_priv #define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off)) #define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off)) -static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg) +static int ep93xx_mdiobus_read(struct mii_bus *bus, int phy_id, int reg) { + struct net_device *dev = bus->priv; struct ep93xx_priv *ep = netdev_priv(dev); int data; int i; @@ -210,8 +216,9 @@ static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg) return data; } -static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data) +static int ep93xx_mdiobus_write(struct mii_bus *bus, int phy_id, int reg, u16 data) { + struct net_device *dev = bus->priv; struct ep93xx_priv *ep = netdev_priv(dev); int i; @@ -224,8 +231,84 @@ static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int d msleep(1); } - if (i == 10) + if (i == 10) { pr_info("mdio write timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int ep93xx_mdiobus_reset(struct mii_bus *bus) +{ + return 0; +} + +static void ep93xx_adjust_link(struct net_device *dev) +{ + struct ep93xx_priv * ep = netdev_priv(dev); + struct phy_device *phydev = ep->phydev; + int status_changed = 0; + + BUG_ON(!phydev); + + if (ep->old_link != phydev->link) { + status_changed = 1; + ep->old_link = phydev->link; + } + + if (phydev->link && (ep->old_duplex != phydev->duplex)) { + status_changed = 1; + ep->old_duplex = phydev->duplex; + } + + if (status_changed) { + pr_info("%s: link %s", dev->name, phydev->link ? + "UP" : "DOWN"); + if (phydev->link) + pr_cont(" - %d/%s", phydev->speed, + DUPLEX_FULL == phydev->duplex ? "full" : "half"); + pr_cont("\n"); + } +} + +static int ep93xx_mii_probe(struct net_device *dev) +{ + struct ep93xx_priv * ep = netdev_priv(dev); + struct phy_device *phydev = NULL; + + /* use platform supplied PHY address if valid */ + if (ep->phy_addr) + phydev = ep->mii_bus->phy_map[ep->phy_addr]; + else + phydev = phy_find_first(ep->mii_bus); + + if (!phydev) { + pr_err("no PHY found\n"); + return -ENODEV; + } + + phydev = phy_connect(dev, dev_name(&phydev->dev), &ep93xx_adjust_link, + 0, PHY_INTERFACE_MODE_MII); + if (IS_ERR(phydev)) { + pr_err("could not attach to PHY\n"); + return PTR_ERR(phydev); + } + + /* mask with MAC supported features */ + phydev->supported &= PHY_BASIC_FEATURES; + phydev->advertising = phydev->supported; + ep->phydev = phydev; + ep->old_link = 0; + ep->old_duplex = -1; + + pr_info("attached PHY driver [%s] " + "(mii_bus:phy_addr=%s)\n", + phydev->drv->name, dev_name(&phydev->dev)); + + phy_start(phydev); + + return 0; } static int ep93xx_rx(struct net_device *dev, int processed, int budget) @@ -570,7 +653,7 @@ static int ep93xx_start_hw(struct net_device *dev) wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9)); /* Does the PHY support preamble suppress? */ - if ((ep93xx_mdio_read(dev, ep->mii.phy_id, MII_BMSR) & 0x0040) != 0) + if ((ep93xx_mdiobus_read(ep->mii_bus, ep->phy_addr, MII_BMSR) & 0x0040) != 0) wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9) | (1 << 8)); /* Receive descriptor ring. */ @@ -703,9 +786,11 @@ static int ep93xx_close(struct net_device *dev) static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct ep93xx_priv *ep = netdev_priv(dev); - struct mii_ioctl_data *data = if_mii(ifr); - return generic_mii_ioctl(&ep->mii, data, cmd, NULL); + if (!ep->phydev) + return -ENODEV; + + return phy_mii_ioctl(ep->phydev, ifr, cmd); } static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -717,25 +802,19 @@ static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct ep93xx_priv *ep = netdev_priv(dev); - return mii_ethtool_gset(&ep->mii, cmd); + return phy_ethtool_gset(ep->phydev, cmd); } static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct ep93xx_priv *ep = netdev_priv(dev); - return mii_ethtool_sset(&ep->mii, cmd); + return phy_ethtool_sset(ep->phydev, cmd); } static int ep93xx_nway_reset(struct net_device *dev) { struct ep93xx_priv *ep = netdev_priv(dev); - return mii_nway_restart(&ep->mii); -} - -static u32 ep93xx_get_link(struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - return mii_link_ok(&ep->mii); + return phy_start_aneg(ep->phydev); } static const struct ethtool_ops ep93xx_ethtool_ops = { @@ -743,7 +822,7 @@ static const struct ethtool_ops ep93xx_ethtool_ops = { .get_settings = ep93xx_get_settings, .set_settings = ep93xx_set_settings, .nway_reset = ep93xx_nway_reset, - .get_link = ep93xx_get_link, + .get_link = ethtool_op_get_link, }; static const struct net_device_ops ep93xx_netdev_ops = { @@ -789,6 +868,11 @@ static int ep93xx_eth_remove(struct platform_device *pdev) /* @@@ Force down. */ unregister_netdev(dev); + + mdiobus_unregister(ep->mii_bus); + kfree(ep->mii_bus->irq); + mdiobus_free(ep->mii_bus); + ep93xx_free_buffers(ep); if (ep->base_addr != NULL) @@ -811,7 +895,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev) struct ep93xx_priv *ep; struct resource *mem; int irq; - int err; + int err = 0; + int i; if (pdev == NULL) return -ENODEV; @@ -849,13 +934,41 @@ static int ep93xx_eth_probe(struct platform_device *pdev) } ep->irq = irq; - ep->mii.phy_id = data->phy_id; - ep->mii.phy_id_mask = 0x1f; - ep->mii.reg_num_mask = 0x1f; - ep->mii.dev = dev; - ep->mii.mdio_read = ep93xx_mdio_read; - ep->mii.mdio_write = ep93xx_mdio_write; + ep->mii_bus = mdiobus_alloc(); + if (!ep->mii_bus) { + dev_err(&pdev->dev, "Failed to allocate mdiobus\n"); + goto err_out; + } + + ep->phy_addr = data->phy_id; + ep->mii_bus->priv = dev; + ep->mii_bus->read = ep93xx_mdiobus_read; + ep->mii_bus->write = ep93xx_mdiobus_write; + ep->mii_bus->reset = ep93xx_mdiobus_reset; + ep->mii_bus->name = "ep93xx_eth_mii"; ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */ + snprintf(ep->mii_bus->id, MII_BUS_ID_SIZE, "%x", + (pdev->id != -1) ? pdev->id : 0); + ep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!ep->mii_bus->irq) { + dev_err(&pdev->dev, "mii_bus irq allocation failed\n"); + goto err_out; + } + + for (i = 0; i < PHY_MAX_ADDR; i++) + ep->mii_bus->irq[i] = PHY_POLL; + + err = mdiobus_register(ep->mii_bus); + if (err) { + dev_err(&pdev->dev, "Failed to register MII bus\n"); + goto err_out; + } + + err = ep93xx_mii_probe(dev); + if (err) { + dev_err(&pdev->dev, "failed to probe MII bus\n"); + goto err_out; + } if (is_zero_ether_addr(dev->dev_addr)) random_ether_addr(dev->dev_addr);