get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/509/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 509,
    "url": "http://patchwork.ozlabs.org/api/patches/509/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20080918124428.GB9157@xi.wantstofly.org/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api",
        "name": "Linux network development",
        "link_name": "netdev",
        "list_id": "netdev.vger.kernel.org",
        "list_email": "netdev@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20080918124428.GB9157@xi.wantstofly.org>",
    "list_archive_url": null,
    "date": "2008-09-18T12:44:28",
    "name": "[PATCH 3/3] mv643xx_eth: convert to phylib",
    "commit_ref": null,
    "pull_url": null,
    "state": "deferred",
    "archived": true,
    "hash": "a8fcc2e20e952d489e6bc335028f7200bd456075",
    "submitter": {
        "id": 94,
        "url": "http://patchwork.ozlabs.org/api/people/94/?format=api",
        "name": "Lennert Buytenhek",
        "email": "buytenh@wantstofly.org"
    },
    "delegate": {
        "id": 36,
        "url": "http://patchwork.ozlabs.org/api/users/36/?format=api",
        "username": "jgarzik",
        "first_name": "Jeff",
        "last_name": "Garzik",
        "email": "jgarzik@pobox.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/20080918124428.GB9157@xi.wantstofly.org/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/509/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/509/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming@ozlabs.org",
        "Delivered-To": "patchwork-incoming@ozlabs.org",
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.176.167])\n\tby ozlabs.org (Postfix) with ESMTP id 18962DDF5A\n\tfor <patchwork-incoming@ozlabs.org>;\n\tThu, 18 Sep 2008 22:44:38 +1000 (EST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1752418AbYIRMob (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tThu, 18 Sep 2008 08:44:31 -0400",
            "(majordomo@vger.kernel.org) by vger.kernel.org id S1752628AbYIRMob\n\t(ORCPT <rfc822; netdev-outgoing>); Thu, 18 Sep 2008 08:44:31 -0400",
            "from xi.wantstofly.org ([83.160.184.112]:40916 \"EHLO\n\txi.wantstofly.org\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1752533AbYIRMo3 (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Thu, 18 Sep 2008 08:44:29 -0400",
            "by xi.wantstofly.org (Postfix, from userid 500)\n\tid 19B837FAC2; Thu, 18 Sep 2008 14:44:28 +0200 (CEST)"
        ],
        "Date": "Thu, 18 Sep 2008 14:44:28 +0200",
        "From": "Lennert Buytenhek <buytenh@wantstofly.org>",
        "To": "Andy Fleming <afleming@freescale.com>",
        "Cc": "netdev@vger.kernel.org",
        "Subject": "Re: [PATCH 3/3] mv643xx_eth: convert to phylib",
        "Message-ID": "<20080918124428.GB9157@xi.wantstofly.org>",
        "References": "<1220448012-20347-1-git-send-email-buytenh@wantstofly.org>\n\t<1220448012-20347-4-git-send-email-buytenh@wantstofly.org>\n\t<A8E7D979-2540-456E-818C-A419D7BE4166@freescale.com>",
        "Mime-Version": "1.0",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "In-Reply-To": "<A8E7D979-2540-456E-818C-A419D7BE4166@freescale.com>",
        "User-Agent": "Mutt/1.4.2.2i",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "On Mon, Sep 15, 2008 at 06:55:18PM -0500, Andy Fleming wrote:\n\n> >@@ -1338,7 +1327,7 @@ static int mv643xx_eth_nway_reset(struct  \n> >net_device *dev)\n> >{\n> >\tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n> >\n> >-\treturn mii_nway_restart(&mp->mii);\n> >+\treturn phy_nway_restart(mp->phy);\n> \n> As mentioned in patch #2, I think you can use genphy_restart_aneg(),  \n> here.\n\nRight, that looks like that'll work.\n\n\n> >static int mv643xx_eth_nway_reset_phyless(struct net_device *dev)\n> >@@ -1350,7 +1339,7 @@ static u32 mv643xx_eth_get_link(struct  \n> >net_device *dev)\n> >{\n> >\tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n> >\n> >-\treturn mii_link_ok(&mp->mii);\n> >+\treturn phy_link_ok(mp->phy);\n> \n> You can just return phydev->link, unless you don't think phydev->link  \n> will be up-to-date.  If so, I recommend using genphy_update_link().   \n> I'm curious: you say the controller handles all the link management.   \n> Is it possible to read that information out?  Since you are doing the  \n> \"do it yourself\" method, it would simplify and speed up certain  \n> options if you just did:\n> \n> phydev->link = readl(somereg) & LINK_STATUS ? 1 : 0\n> \n> You could do that whenever the controller tells you the link is down.\n\nYes, e.g. this works:\n\n\tstatic u32 mv643xx_eth_get_link(struct net_device *dev)\n\t{\n\t\tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n\n\t\treturn !!(rdl(mp, PORT_STATUS(mp->port_num)) & LINK_UP);\n\t}\n\nI wonder if I need to update ->link at all, considering that I don't\nuse it, and I don't call any phylib functionality that uses it.\n\n\n> >+static void phy_init(struct mv643xx_eth_private *mp, int speed, int  \n> >duplex)\n> >{\n> >\tstruct ethtool_cmd cmd;\n> >-\tint err;\n> >\n> >-\terr = phy_detect(mp);\n> >-\tif (err) {\n> >-\t\tdev_printk(KERN_INFO, &mp->dev->dev,\n> >-\t\t\t   \"no PHY detected at addr %d\\n\", mp->phy_addr);\n> >-\t\treturn err;\n> >-\t}\n> >\tphy_reset(mp);\n> >\n> >-\tmp->mii.phy_id = mp->phy_addr;\n> >-\tmp->mii.phy_id_mask = 0x3f;\n> >-\tmp->mii.reg_num_mask = 0x1f;\n> >-\tmp->mii.dev = mp->dev;\n> >-\tmp->mii.mdio_read = mv643xx_eth_mdio_read;\n> >-\tmp->mii.mdio_write = mv643xx_eth_mdio_write;\n> >-\n> >-\tmp->mii.supports_gmii = mii_check_gmii_support(&mp->mii);\n> >+\tphy_attach(mp->dev, mp->phy->dev.bus_id, 0, 0);\n> >\n> >\tmemset(&cmd, 0, sizeof(cmd));\n> >\n> >\tcmd.port = PORT_MII;\n> >\tcmd.transceiver = XCVR_INTERNAL;\n> >-\tcmd.phy_address = mp->phy_addr;\n> >-\tif (pd->speed == 0) {\n> >+\tcmd.phy_address = mp->phy->addr;\n> >+\tif (speed == 0) {\n> >\t\tcmd.autoneg = AUTONEG_ENABLE;\n> >\t\tcmd.speed = SPEED_100;\n> >\t\tcmd.advertising = ADVERTISED_10baseT_Half  |\n> >\t\t\t\t  ADVERTISED_10baseT_Full  |\n> >\t\t\t\t  ADVERTISED_100baseT_Half |\n> >\t\t\t\t  ADVERTISED_100baseT_Full;\n> >-\t\tif (mp->mii.supports_gmii)\n> >+\t\tif (phy_check_gmii_support(mp->phy))\n> >\t\t\tcmd.advertising |= ADVERTISED_1000baseT_Full;\n> >\t} else {\n> >\t\tcmd.autoneg = AUTONEG_DISABLE;\n> >-\t\tcmd.speed = pd->speed;\n> >-\t\tcmd.duplex = pd->duplex;\n> >+\t\tcmd.speed = speed;\n> >+\t\tcmd.duplex = duplex;\n> >\t}\n> >\n> >\tmv643xx_eth_set_settings(mp->dev, &cmd);\n> \n> This is a somewhat roundabout way to configure the PHY.   \n> The ..._sset() function was intended to provide support for userspace  \n> configuration of the PHY via the same interface ethtool uses.  There  \n> are more direct ways to configure the PHY when you have a pointer to a  \n> struct phy_device.\n\nACK.  I was just doing the same thing as the old code did -- which I\ninherited from somewhere else.\n\n\n> Look at the code for phy_ethtool_sset(), and replicate what it does.   \n> That way you don't need to set up the struct ethtool_cmd.  The  \n> definitions for the fields are identical, so it should just mean  \n> replacing all the cmd.foo = bar lines with mp->phy->foo = bar.\n> \n> And, actually, I believe you can reduce this even more, since you are  \n> just doing the generic initialization from what I can tell.  You can  \n> just set mp->phy->supported and ->advertising to be what your  \n> controller supports (masked with what the connected PHY supports), and  \n> then invoke phy_start_aneg(mp->phy);  phylib will configure the PHY  \n> properly, and then return control to you.\n\nI'll make this function:\n\n\tstatic void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex)\n\t{\n\t\tstruct phy_device *phy = mp->phy;\n\n\t\tphy_reset(mp);\n\n\t\tphy_attach(mp->dev, phy->dev.bus_id, 0, PHY_INTERFACE_MODE_GMII);\n\n\t\tphy->state = PHY_HALTED;\n\n\t\tif (speed == 0) {\n\t\t\tphy->autoneg = AUTONEG_ENABLE;\n\t\t\tphy->speed = 0;\n\t\t\tphy->duplex = 0;\n\t\t\tphy->advertising = phy->supported | ADVERTISED_Autoneg;\n\t\t} else {\n\t\t\tphy->autoneg = AUTONEG_DISABLE;\n\t\t\tphy->advertising = 0;\n\t\t\tphy->speed = speed;\n\t\t\tphy->duplex = duplex;\n\t\t}\n\t\tphy_start_aneg(phy);\n\t}\n\nOK?  (PHY_HALTED because that seems to be the way to stop the state\nmachine from running at all.  Or should I call phy_stop() once?)\n\n\n> You will, however, need to  \n> figure out how best to read out the status for the PHY, and how to  \n> know when autonegotiation is done.  I'm assuming that your controller  \n> tracks that information, and that you can manually pull that  \n> information from local register space (rather than the SMI bus).\n\nI don't really need to access it all during normal operation -- the\ncontroller just reads the link up/down and speed and duplex bits from\nthe PHY automatically and then configures itself accordingly.  The\nonly time I need to access this information is when someone asks for\nit via ethtool (or if I want to print a link status message).  I.e. I\ndon't need any state machine, be it phylib's or my own.\n\n\n\nNew patch:\n\n\ncommit 61c35c0299272a4f8d8fb8d3dd59a9742fb34f35\nAuthor: Lennert Buytenhek <buytenh@wantstofly.org>\nDate:   Tue Aug 26 13:34:19 2008 +0200\n\n    mv643xx_eth: convert to phylib\n    \n    Switch mv643xx_eth from using drivers/net/mii.c to using phylib.\n    \n    Since the mv643xx_eth hardware does all the link state handling and\n    PHY polling, the driver will use phylib in the \"Doing it all yourself\"\n    mode described in the phylib documentation.\n    \n    Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>",
    "diff": "diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig\nindex 4a11296..d85d760 100644\n--- a/drivers/net/Kconfig\n+++ b/drivers/net/Kconfig\n@@ -2262,7 +2262,7 @@ config UGETH_TX_ON_DEMAND\n config MV643XX_ETH\n \ttristate \"Marvell Discovery (643XX) and Orion ethernet support\"\n \tdepends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION\n-\tselect MII\n+\tselect PHYLIB\n \thelp\n \t  This driver supports the gigabit ethernet MACs in the\n \t  Marvell Discovery PPC/MIPS chipset family (MV643XX) and\ndiff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c\nindex d32d874..ee19975 100644\n--- a/drivers/net/mv643xx_eth.c\n+++ b/drivers/net/mv643xx_eth.c\n@@ -48,7 +48,7 @@\n #include <linux/kernel.h>\n #include <linux/spinlock.h>\n #include <linux/workqueue.h>\n-#include <linux/mii.h>\n+#include <linux/phy.h>\n #include <linux/mv643xx_eth.h>\n #include <asm/io.h>\n #include <asm/types.h>\n@@ -248,9 +248,9 @@ struct mv643xx_eth_shared_private {\n \tstruct mv643xx_eth_shared_private *smi;\n \n \t/*\n-\t * Protects access to SMI_REG, which is shared between ports.\n+\t * Provides access to local SMI interface.\n \t */\n-\tstruct mutex phy_lock;\n+\tstruct mii_bus smi_bus;\n \n \t/*\n \t * If we have access to the error interrupt pin (which is\n@@ -354,11 +354,10 @@ struct mv643xx_eth_private {\n \n \tstruct net_device *dev;\n \n-\tint phy_addr;\n+\tstruct phy_device *phy;\n \n \tstruct mib_counters mib_counters;\n \tstruct work_struct tx_timeout_task;\n-\tstruct mii_if_info mii;\n \n \tstruct napi_struct napi;\n \tu8 work_link;\n@@ -1077,62 +1076,50 @@ static int smi_wait_ready(struct mv643xx_eth_shared_private *msp)\n \treturn 0;\n }\n \n-static int smi_reg_read(struct mv643xx_eth_private *mp,\n-\t\t\tunsigned int addr, unsigned int reg)\n+static int smi_bus_read(struct mii_bus *bus, int addr, int reg)\n {\n-\tstruct mv643xx_eth_shared_private *msp = mp->shared->smi;\n+\tstruct mv643xx_eth_shared_private *msp = bus->priv;\n \tvoid __iomem *smi_reg = msp->base + SMI_REG;\n \tint ret;\n \n-\tmutex_lock(&msp->phy_lock);\n-\n \tif (smi_wait_ready(msp)) {\n-\t\tprintk(\"%s: SMI bus busy timeout\\n\", mp->dev->name);\n-\t\tret = -ETIMEDOUT;\n-\t\tgoto out;\n+\t\tprintk(\"mv643xx_eth: SMI bus busy timeout\\n\");\n+\t\treturn -ETIMEDOUT;\n \t}\n \n \twritel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg);\n \n \tif (smi_wait_ready(msp)) {\n-\t\tprintk(\"%s: SMI bus busy timeout\\n\", mp->dev->name);\n-\t\tret = -ETIMEDOUT;\n-\t\tgoto out;\n+\t\tprintk(\"mv643xx_eth: SMI bus busy timeout\\n\");\n+\t\treturn -ETIMEDOUT;\n \t}\n \n \tret = readl(smi_reg);\n \tif (!(ret & SMI_READ_VALID)) {\n-\t\tprintk(\"%s: SMI bus read not valid\\n\", mp->dev->name);\n-\t\tret = -ENODEV;\n-\t\tgoto out;\n+\t\tprintk(\"mv643xx_eth: SMI bus read not valid\\n\");\n+\t\treturn -ENODEV;\n \t}\n \n-\tret &= 0xffff;\n-\n-out:\n-\tmutex_unlock(&msp->phy_lock);\n-\n-\treturn ret;\n+\treturn ret & 0xffff;\n }\n \n-static int smi_reg_write(struct mv643xx_eth_private *mp, unsigned int addr,\n-\t\t\t unsigned int reg, unsigned int value)\n+static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val)\n {\n-\tstruct mv643xx_eth_shared_private *msp = mp->shared->smi;\n+\tstruct mv643xx_eth_shared_private *msp = bus->priv;\n \tvoid __iomem *smi_reg = msp->base + SMI_REG;\n \n-\tmutex_lock(&msp->phy_lock);\n-\n \tif (smi_wait_ready(msp)) {\n-\t\tprintk(\"%s: SMI bus busy timeout\\n\", mp->dev->name);\n-\t\tmutex_unlock(&msp->phy_lock);\n+\t\tprintk(\"mv643xx_eth: SMI bus busy timeout\\n\");\n \t\treturn -ETIMEDOUT;\n \t}\n \n \twritel(SMI_OPCODE_WRITE | (reg << 21) |\n-\t\t(addr << 16) | (value & 0xffff), smi_reg);\n+\t\t(addr << 16) | (val & 0xffff), smi_reg);\n \n-\tmutex_unlock(&msp->phy_lock);\n+\tif (smi_wait_ready(msp)) {\n+\t\tprintk(\"mv643xx_eth: SMI bus busy timeout\\n\");\n+\t\treturn -ETIMEDOUT;\n+\t}\n \n \treturn 0;\n }\n@@ -1277,7 +1264,9 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *\n \tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n \tint err;\n \n-\terr = mii_ethtool_gset(&mp->mii, cmd);\n+\terr = phy_read_status(mp->phy);\n+\tif (err == 0)\n+\t\terr = phy_ethtool_gset(mp->phy, cmd);\n \n \t/*\n \t * The MAC does not support 1000baseT_Half.\n@@ -1331,7 +1320,7 @@ static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *\n \t */\n \tcmd->advertising &= ~ADVERTISED_1000baseT_Half;\n \n-\treturn mii_ethtool_sset(&mp->mii, cmd);\n+\treturn phy_ethtool_sset(mp->phy, cmd);\n }\n \n static int mv643xx_eth_set_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd)\n@@ -1353,7 +1342,7 @@ static int mv643xx_eth_nway_reset(struct net_device *dev)\n {\n \tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n \n-\treturn mii_nway_restart(&mp->mii);\n+\treturn genphy_restart_aneg(mp->phy);\n }\n \n static int mv643xx_eth_nway_reset_phyless(struct net_device *dev)\n@@ -1365,12 +1354,7 @@ static u32 mv643xx_eth_get_link(struct net_device *dev)\n {\n \tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n \n-\treturn mii_link_ok(&mp->mii);\n-}\n-\n-static u32 mv643xx_eth_get_link_phyless(struct net_device *dev)\n-{\n-\treturn 1;\n+\treturn !!(rdl(mp, PORT_STATUS(mp->port_num)) & LINK_UP);\n }\n \n static void mv643xx_eth_get_strings(struct net_device *dev,\n@@ -1438,7 +1422,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = {\n \t.set_settings\t\t= mv643xx_eth_set_settings_phyless,\n \t.get_drvinfo\t\t= mv643xx_eth_get_drvinfo,\n \t.nway_reset\t\t= mv643xx_eth_nway_reset_phyless,\n-\t.get_link\t\t= mv643xx_eth_get_link_phyless,\n+\t.get_link\t\t= mv643xx_eth_get_link,\n \t.set_sg\t\t\t= ethtool_op_set_sg,\n \t.get_strings\t\t= mv643xx_eth_get_strings,\n \t.get_ethtool_stats\t= mv643xx_eth_get_ethtool_stats,\n@@ -1931,16 +1915,16 @@ static void phy_reset(struct mv643xx_eth_private *mp)\n {\n \tint data;\n \n-\tdata = smi_reg_read(mp, mp->phy_addr, MII_BMCR);\n+\tdata = phy_read(mp->phy, MII_BMCR);\n \tif (data < 0)\n \t\treturn;\n \n \tdata |= BMCR_RESET;\n-\tif (smi_reg_write(mp, mp->phy_addr, MII_BMCR, data) < 0)\n+\tif (phy_write(mp->phy, MII_BMCR, data) < 0)\n \t\treturn;\n \n \tdo {\n-\t\tdata = smi_reg_read(mp, mp->phy_addr, MII_BMCR);\n+\t\tdata = phy_read(mp->phy, MII_BMCR);\n \t} while (data >= 0 && data & BMCR_RESET);\n }\n \n@@ -1952,7 +1936,7 @@ static void port_start(struct mv643xx_eth_private *mp)\n \t/*\n \t * Perform PHY reset, if there is a PHY.\n \t */\n-\tif (mp->phy_addr != -1) {\n+\tif (mp->phy != NULL) {\n \t\tstruct ethtool_cmd cmd;\n \n \t\tmv643xx_eth_get_settings(mp->dev, &cmd);\n@@ -1969,7 +1953,7 @@ static void port_start(struct mv643xx_eth_private *mp)\n \twrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);\n \n \tpscr |= DO_NOT_FORCE_LINK_FAIL;\n-\tif (mp->phy_addr == -1)\n+\tif (mp->phy == NULL)\n \t\tpscr |= FORCE_LINK_PASS;\n \twrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr);\n \n@@ -2175,8 +2159,8 @@ static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)\n {\n \tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n \n-\tif (mp->phy_addr != -1)\n-\t\treturn generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL);\n+\tif (mp->phy != NULL)\n+\t\treturn phy_mii_ioctl(mp->phy, if_mii(ifr), cmd);\n \n \treturn -EOPNOTSUPP;\n }\n@@ -2246,18 +2230,6 @@ static void mv643xx_eth_netpoll(struct net_device *dev)\n }\n #endif\n \n-static int mv643xx_eth_mdio_read(struct net_device *dev, int addr, int reg)\n-{\n-\tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n-\treturn smi_reg_read(mp, addr, reg);\n-}\n-\n-static void mv643xx_eth_mdio_write(struct net_device *dev, int addr, int reg, int val)\n-{\n-\tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n-\tsmi_reg_write(mp, addr, reg, val);\n-}\n-\n \n /* platform glue ************************************************************/\n static void\n@@ -2352,11 +2324,23 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)\n \tif (msp->base == NULL)\n \t\tgoto out_free;\n \n-\tmsp->smi = msp;\n-\tif (pd != NULL && pd->shared_smi != NULL)\n+\t/*\n+\t * Set up and register SMI bus.\n+\t */\n+\tif (pd == NULL || pd->shared_smi == NULL) {\n+\t\tmsp->smi_bus.priv = msp;\n+\t\tmsp->smi_bus.name = \"mv643xx_eth smi\";\n+\t\tmsp->smi_bus.read = smi_bus_read;\n+\t\tmsp->smi_bus.write = smi_bus_write,\n+\t\tsnprintf(msp->smi_bus.id, MII_BUS_ID_SIZE, \"%d\", pdev->id);\n+\t\tmsp->smi_bus.dev = &pdev->dev;\n+\t\tmsp->smi_bus.phy_mask = 0xffffffff;\n+\t\tif (mdiobus_register(&msp->smi_bus) < 0)\n+\t\t\tgoto out_unmap;\n+\t\tmsp->smi = msp;\n+\t} else {\n \t\tmsp->smi = platform_get_drvdata(pd->shared_smi);\n-\n-\tmutex_init(&msp->phy_lock);\n+\t}\n \n \tmsp->err_interrupt = NO_IRQ;\n \tinit_waitqueue_head(&msp->smi_busy_wait);\n@@ -2392,6 +2376,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)\n \n \treturn 0;\n \n+out_unmap:\n+\tiounmap(msp->base);\n out_free:\n \tkfree(msp);\n out:\n@@ -2401,7 +2387,10 @@ out:\n static int mv643xx_eth_shared_remove(struct platform_device *pdev)\n {\n \tstruct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev);\n+\tstruct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;\n \n+\tif (pd == NULL || pd->shared_smi == NULL)\n+\t\tmdiobus_unregister(&msp->smi_bus);\n \tif (msp->err_interrupt != NO_IRQ)\n \t\tfree_irq(msp->err_interrupt, msp);\n \tiounmap(msp->base);\n@@ -2449,17 +2438,6 @@ static void set_params(struct mv643xx_eth_private *mp,\n \telse\n \t\tuc_addr_get(mp, dev->dev_addr);\n \n-\tif (pd->phy_addr == MV643XX_ETH_PHY_NONE) {\n-\t\tmp->phy_addr = -1;\n-\t} else {\n-\t\tif (pd->phy_addr != MV643XX_ETH_PHY_ADDR_DEFAULT) {\n-\t\t\tmp->phy_addr = pd->phy_addr & 0x3f;\n-\t\t\tphy_addr_set(mp, mp->phy_addr);\n-\t\t} else {\n-\t\t\tmp->phy_addr = phy_addr_get(mp);\n-\t\t}\n-\t}\n-\n \tmp->default_rx_ring_size = DEFAULT_RX_QUEUE_SIZE;\n \tif (pd->rx_queue_size)\n \t\tmp->default_rx_ring_size = pd->rx_queue_size;\n@@ -2477,76 +2455,62 @@ static void set_params(struct mv643xx_eth_private *mp,\n \tmp->txq_count = pd->tx_queue_count ? : 1;\n }\n \n-static int phy_detect(struct mv643xx_eth_private *mp)\n+static struct phy_device *phy_scan(struct mv643xx_eth_private *mp,\n+\t\t\t\t   int phy_addr)\n {\n-\tint data;\n-\tint data2;\n-\n-\tdata = smi_reg_read(mp, mp->phy_addr, MII_BMCR);\n-\tif (data < 0)\n-\t\treturn -ENODEV;\n+\tstruct mii_bus *bus = &mp->shared->smi->smi_bus;\n+\tstruct phy_device *phydev;\n+\tint start;\n+\tint num;\n+\tint i;\n \n-\tif (smi_reg_write(mp, mp->phy_addr, MII_BMCR, data ^ BMCR_ANENABLE) < 0)\n-\t\treturn -ENODEV;\n+\tif (phy_addr == MV643XX_ETH_PHY_ADDR_DEFAULT) {\n+\t\tstart = phy_addr_get(mp) & 0x1f;\n+\t\tnum = 32;\n+\t} else {\n+\t\tstart = phy_addr & 0x1f;\n+\t\tnum = 1;\n+\t}\n \n-\tdata2 = smi_reg_read(mp, mp->phy_addr, MII_BMCR);\n-\tif (data2 < 0)\n-\t\treturn -ENODEV;\n+\tphydev = NULL;\n+\tfor (i = 0; i < num; i++) {\n+\t\tint addr = (start + i) & 0x1f;\n \n-\tif (((data ^ data2) & BMCR_ANENABLE) == 0)\n-\t\treturn -ENODEV;\n+\t\tif (bus->phy_map[addr] == NULL)\n+\t\t\tmdiobus_scan(bus, addr);\n \n-\tsmi_reg_write(mp, mp->phy_addr, MII_BMCR, data);\n+\t\tif (phydev == NULL) {\n+\t\t\tphydev = bus->phy_map[addr];\n+\t\t\tif (phydev != NULL)\n+\t\t\t\tphy_addr_set(mp, addr);\n+\t\t}\n+\t}\n \n-\treturn 0;\n+\treturn phydev;\n }\n \n-static int phy_init(struct mv643xx_eth_private *mp,\n-\t\t    struct mv643xx_eth_platform_data *pd)\n+static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex)\n {\n-\tstruct ethtool_cmd cmd;\n-\tint err;\n+\tstruct phy_device *phy = mp->phy;\n \n-\terr = phy_detect(mp);\n-\tif (err) {\n-\t\tdev_printk(KERN_INFO, &mp->dev->dev,\n-\t\t\t   \"no PHY detected at addr %d\\n\", mp->phy_addr);\n-\t\treturn err;\n-\t}\n \tphy_reset(mp);\n \n-\tmp->mii.phy_id = mp->phy_addr;\n-\tmp->mii.phy_id_mask = 0x3f;\n-\tmp->mii.reg_num_mask = 0x1f;\n-\tmp->mii.dev = mp->dev;\n-\tmp->mii.mdio_read = mv643xx_eth_mdio_read;\n-\tmp->mii.mdio_write = mv643xx_eth_mdio_write;\n-\n-\tmp->mii.supports_gmii = mii_check_gmii_support(&mp->mii);\n-\n-\tmemset(&cmd, 0, sizeof(cmd));\n-\n-\tcmd.port = PORT_MII;\n-\tcmd.transceiver = XCVR_INTERNAL;\n-\tcmd.phy_address = mp->phy_addr;\n-\tif (pd->speed == 0) {\n-\t\tcmd.autoneg = AUTONEG_ENABLE;\n-\t\tcmd.speed = SPEED_100;\n-\t\tcmd.advertising = ADVERTISED_10baseT_Half  |\n-\t\t\t\t  ADVERTISED_10baseT_Full  |\n-\t\t\t\t  ADVERTISED_100baseT_Half |\n-\t\t\t\t  ADVERTISED_100baseT_Full;\n-\t\tif (mp->mii.supports_gmii)\n-\t\t\tcmd.advertising |= ADVERTISED_1000baseT_Full;\n-\t} else {\n-\t\tcmd.autoneg = AUTONEG_DISABLE;\n-\t\tcmd.speed = pd->speed;\n-\t\tcmd.duplex = pd->duplex;\n-\t}\n+\tphy_attach(mp->dev, phy->dev.bus_id, 0, PHY_INTERFACE_MODE_GMII);\n \n-\tmv643xx_eth_set_settings(mp->dev, &cmd);\n+\tphy->state = PHY_HALTED;\n \n-\treturn 0;\n+\tif (speed == 0) {\n+\t\tphy->autoneg = AUTONEG_ENABLE;\n+\t\tphy->speed = 0;\n+\t\tphy->duplex = 0;\n+\t\tphy->advertising = phy->supported | ADVERTISED_Autoneg;\n+\t} else {\n+\t\tphy->autoneg = AUTONEG_DISABLE;\n+\t\tphy->advertising = 0;\n+\t\tphy->speed = speed;\n+\t\tphy->duplex = duplex;\n+\t}\n+\tphy_start_aneg(phy);\n }\n \n static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex)\n@@ -2560,7 +2524,7 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex)\n \t}\n \n \tpscr = MAX_RX_PACKET_9700BYTE | SERIAL_PORT_CONTROL_RESERVED;\n-\tif (mp->phy_addr == -1) {\n+\tif (mp->phy == NULL) {\n \t\tpscr |= DISABLE_AUTO_NEG_SPEED_GMII;\n \t\tif (speed == SPEED_1000)\n \t\t\tpscr |= SET_GMII_SPEED_TO_1000;\n@@ -2614,20 +2578,20 @@ static int mv643xx_eth_probe(struct platform_device *pdev)\n \tset_params(mp, pd);\n \tdev->real_num_tx_queues = mp->txq_count;\n \n-\tmib_counters_clear(mp);\n-\tINIT_WORK(&mp->tx_timeout_task, tx_timeout_task);\n-\n-\tif (mp->phy_addr != -1) {\n-\t\terr = phy_init(mp, pd);\n-\t\tif (err)\n-\t\t\tgoto out;\n+\tif (pd->phy_addr != MV643XX_ETH_PHY_NONE)\n+\t\tmp->phy = phy_scan(mp, pd->phy_addr);\n \n+\tif (mp->phy != NULL) {\n+\t\tphy_init(mp, pd->speed, pd->duplex);\n \t\tSET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);\n \t} else {\n \t\tSET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops_phyless);\n \t}\n+\n \tinit_pscr(mp, pd->speed, pd->duplex);\n \n+\tmib_counters_clear(mp);\n+\tINIT_WORK(&mp->tx_timeout_task, tx_timeout_task);\n \tnetif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 128);\n \n \tinit_timer(&mp->rx_oom);\n@@ -2685,6 +2649,8 @@ static int mv643xx_eth_remove(struct platform_device *pdev)\n \tstruct mv643xx_eth_private *mp = platform_get_drvdata(pdev);\n \n \tunregister_netdev(mp->dev);\n+\tif (mp->phy != NULL)\n+\t\tphy_detach(mp->phy);\n \tflush_scheduled_work();\n \tfree_netdev(mp->dev);\n \n",
    "prefixes": [
        "3/3"
    ]
}