All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] b44: add support for external PHY
@ 2013-12-19  1:28 Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver Hauke Mehrtens
                   ` (8 more replies)
  0 siblings, 9 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

This adds support for an external phy connected to the mac controlled 
by b44. This is used on home routers of the BCM47xx line where this MAC 
core was used and is contended to an external switch core through MII. 
These patches are in OpenWrt for some time and are tested by different 
users with different devices.

This also does some changes to the fixed phy driver.

v2: 
 - add fixed phy driver patch
 - use fixed phy driver in b44
 - some smaller changes and typos

Hauke Mehrtens (9):
  fixed-phy: register fixed PHY as platform driver
  b44: check register instead of PHY address to detect external PHY
  b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY
  b44: abort when no PHY is available at all
  b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii
  b44: add phylib support
  b44: activate PHY when MAC is off
  b44: do not set PHY address to 30 for every ext PHY
  b44: use fixed PHY device if we do not find any

 arch/mips/ar7/platform.c              |   39 ++++-
 drivers/net/ethernet/broadcom/Kconfig |    1 +
 drivers/net/ethernet/broadcom/b44.c   |  276 ++++++++++++++++++++++++++++++---
 drivers/net/ethernet/broadcom/b44.h   |   15 +-
 drivers/net/phy/fixed.c               |   79 +++++-----
 include/linux/phy_fixed.h             |   21 +--
 6 files changed, 349 insertions(+), 82 deletions(-)

-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  2013-12-19  1:48   ` Florian Fainelli
  2013-12-19  1:28 ` [PATCH v2 2/9] b44: check register instead of PHY address to detect external PHY Hauke Mehrtens
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem
  Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens, Florian Fainelli,
	Vitaly Bordug, Anton Vorontsov

This changes the fixed phy driver from registering the mdio bus when
the module gets loaded to registering it when a device was registered.
A phy has to get registered to this driver before it registered the
mdio bus, but this only worked when the phys are registered in some
arch code before the system booted completely. Now we want to do so
when the Ethernet driver gets initialized which could be happen every
time.

To make this driver work with such a case, convert it to a platform
driver which could be registered every time with the phys which should
be on the bus.

This was only tested on BCM47XX, but not on AR7 because I do not have
such a device.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
CC: Florian Fainelli <florian@openwrt.org>
CC: Vitaly Bordug <vbordug@ru.mvista.com>
CC: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 arch/mips/ar7/platform.c  |   39 ++++++++++++++++++----
 drivers/net/phy/fixed.c   |   79 ++++++++++++++++++++++-----------------------
 include/linux/phy_fixed.h |   21 ++++++------
 3 files changed, 83 insertions(+), 56 deletions(-)

diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
index 7e2356f..26ea35a 100644
--- a/arch/mips/ar7/platform.c
+++ b/arch/mips/ar7/platform.c
@@ -251,10 +251,35 @@ static struct resource cpmac_high_res[] = {
 	},
 };
 
-static struct fixed_phy_status fixed_phy_status __initdata = {
-	.link		= 1,
-	.speed		= 100,
-	.duplex		= 1,
+static struct pdata_fixed_phy cpmac_phy_data = {
+	.name 		= "fixed-0",
+	.phys_num	= 1,
+	.phys		= {{
+		.phy_id	= 1,
+		.irq	= PHY_POLL,
+		.status = {
+			.link	= 1,
+			.speed	= 100,
+			.duplex	= 1,
+		},
+	},
+	{
+		.phy_id	= 1,
+		.irq	= PHY_POLL,
+		.status = {
+			.link	= 1,
+			.speed	= 100,
+			.duplex	= 1,
+		},
+	}},
+};
+
+static struct platform_device cpmac_phy = {
+	.id		= 0,
+	.name		= "fixed-phy",
+	.dev = {
+		.platform_data	= &cpmac_phy_data,
+	},
 };
 
 static struct plat_cpmac_data cpmac_low_data = {
@@ -683,7 +708,8 @@ static int __init ar7_register_devices(void)
 	}
 
 	if (ar7_has_high_cpmac()) {
-		res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status);
+		cpmac_phy_data.phys[1].phy_id = cpmac_high.id;
+		cpmac_phy_data.phys_num = 2;
 		if (!res) {
 			cpmac_get_mac(1, cpmac_high_data.dev_addr);
 
@@ -695,7 +721,8 @@ static int __init ar7_register_devices(void)
 	} else
 		cpmac_low_data.phy_mask = 0xffffffff;
 
-	res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status);
+	cpmac_phy_data.phys[0].phy_id = cpmac_low.id;
+	res = platform_device_register(&cpmac_phy);
 	if (!res) {
 		cpmac_get_mac(0, cpmac_low_data.dev_addr);
 		res = platform_device_register(&cpmac_low);
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index ba55adf..dd5154b 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -5,6 +5,7 @@
  *         Anton Vorontsov <avorontsov@ru.mvista.com>
  *
  * Copyright (c) 2006-2007 MontaVista Software, Inc.
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -39,11 +40,6 @@ struct fixed_phy {
 	struct list_head node;
 };
 
-static struct platform_device *pdev;
-static struct fixed_mdio_bus platform_fmb = {
-	.phys = LIST_HEAD_INIT(platform_fmb.phys),
-};
-
 static int fixed_phy_update_regs(struct fixed_phy *fp)
 {
 	u16 bmsr = BMSR_ANEGCAPABLE;
@@ -153,7 +149,7 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
 			      int (*link_update)(struct net_device *,
 						 struct fixed_phy_status *))
 {
-	struct fixed_mdio_bus *fmb = &platform_fmb;
+	struct fixed_mdio_bus *fmb = phydev->bus->priv;
 	struct fixed_phy *fp;
 
 	if (!link_update || !phydev || !phydev->bus)
@@ -171,14 +167,14 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
 }
 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
 
-int fixed_phy_add(unsigned int irq, int phy_id,
-		  struct fixed_phy_status *status)
+static int fixed_phy_add(struct device *dev, struct fixed_mdio_bus *fmb,
+			 unsigned int irq, int phy_id,
+			 struct fixed_phy_status *status)
 {
 	int ret;
-	struct fixed_mdio_bus *fmb = &platform_fmb;
 	struct fixed_phy *fp;
 
-	fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+	fp = devm_kzalloc(dev, sizeof(struct fixed_phy), GFP_KERNEL);
 	if (!fp)
 		return -ENOMEM;
 
@@ -191,36 +187,41 @@ int fixed_phy_add(unsigned int irq, int phy_id,
 
 	ret = fixed_phy_update_regs(fp);
 	if (ret)
-		goto err_regs;
+		return ret;
 
 	list_add_tail(&fp->node, &fmb->phys);
 
 	return 0;
-
-err_regs:
-	kfree(fp);
-	return ret;
 }
-EXPORT_SYMBOL_GPL(fixed_phy_add);
 
-static int __init fixed_mdio_bus_init(void)
+static int fixed_phy_probe(struct platform_device *pdev)
 {
-	struct fixed_mdio_bus *fmb = &platform_fmb;
+	struct pdata_fixed_phy *pdata = dev_get_platdata(&pdev->dev);
+	struct fixed_mdio_bus *fmb;
+	struct fixed_phy_conf *phy;
 	int ret;
+	int i;
 
-	pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
-	if (IS_ERR(pdev)) {
-		ret = PTR_ERR(pdev);
-		goto err_pdev;
+	fmb = devm_kzalloc(&pdev->dev, sizeof(struct fixed_mdio_bus), GFP_KERNEL);
+	if (!fmb)
+		return -ENOMEM;
+	INIT_LIST_HEAD(&fmb->phys);
+	platform_set_drvdata(pdev, fmb);
+
+	for (i = 0; i < pdata->phys_num; i++) {
+		phy = &pdata->phys[i];
+		ret = fixed_phy_add(&pdev->dev, fmb, phy->irq, phy->phy_id,
+				    &phy->status);
+		if (ret < 0)
+			return ret;
 	}
 
 	fmb->mii_bus = mdiobus_alloc();
-	if (fmb->mii_bus == NULL) {
-		ret = -ENOMEM;
-		goto err_mdiobus_reg;
+	if (!fmb->mii_bus) {
+		return -ENOMEM;
 	}
 
-	snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
+	snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, pdata->name);
 	fmb->mii_bus->name = "Fixed MDIO Bus";
 	fmb->mii_bus->priv = fmb;
 	fmb->mii_bus->parent = &pdev->dev;
@@ -236,29 +237,27 @@ static int __init fixed_mdio_bus_init(void)
 
 err_mdiobus_alloc:
 	mdiobus_free(fmb->mii_bus);
-err_mdiobus_reg:
-	platform_device_unregister(pdev);
-err_pdev:
 	return ret;
 }
-module_init(fixed_mdio_bus_init);
 
-static void __exit fixed_mdio_bus_exit(void)
+static int fixed_phy_remove(struct platform_device *pdev)
 {
-	struct fixed_mdio_bus *fmb = &platform_fmb;
-	struct fixed_phy *fp, *tmp;
+	struct fixed_mdio_bus *fmb = platform_get_drvdata(pdev);
 
 	mdiobus_unregister(fmb->mii_bus);
 	mdiobus_free(fmb->mii_bus);
-	platform_device_unregister(pdev);
-
-	list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
-		list_del(&fp->node);
-		kfree(fp);
-	}
+	return 0;
 }
-module_exit(fixed_mdio_bus_exit);
 
+static struct platform_driver fixed_phy_driver = {
+	.probe = fixed_phy_probe,
+	.remove = fixed_phy_remove,
+	.driver = {
+		.name = "fixed-phy",
+	},
+};
+
+module_platform_driver(fixed_phy_driver);
 MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
 MODULE_AUTHOR("Vitaly Bordug");
 MODULE_LICENSE("GPL");
diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h
index 509d8f5..f41140e 100644
--- a/include/linux/phy_fixed.h
+++ b/include/linux/phy_fixed.h
@@ -9,16 +9,17 @@ struct fixed_phy_status {
 	int asym_pause;
 };
 
-#ifdef CONFIG_FIXED_PHY
-extern int fixed_phy_add(unsigned int irq, int phy_id,
-			 struct fixed_phy_status *status);
-#else
-static inline int fixed_phy_add(unsigned int irq, int phy_id,
-				struct fixed_phy_status *status)
-{
-	return -ENODEV;
-}
-#endif /* CONFIG_FIXED_PHY */
+struct fixed_phy_conf {
+	int phy_id;
+	unsigned int irq;
+	struct fixed_phy_status status;
+};
+
+struct pdata_fixed_phy {
+	char *name;
+	unsigned int phys_num;
+	struct fixed_phy_conf phys[];
+};
 
 /*
  * This function issued only by fixed_phy-aware drivers, no need
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 2/9] b44: check register instead of PHY address to detect external PHY
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 3/9] b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY Hauke Mehrtens
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

The Ethernet core supported by b44 supports an internal PHY integrated
into the mac core, which is supported by the b44 driver and an external
PHY to which the mac core is connected. This external PHY could be a
switch connected through MII, which is often the case when this core is
used on home routers. The usage of an external PHY was assumed when the
PHY address 30 was used and an internal PHY was assumed when the PHY
address was different. To verify that b44_phy_reset() was called and
checked if it worked, otherwise PHY address 30 was assumed, an external
PHY. It is better to check the register which says which PHY is
connected to the MAC instead of checking the PHY address.
The interface to an external PHY was only activated when this register
was set.

This also changes B44_FLAG_INTERNAL_PHY to B44_FLAG_EXTERNAL_PHY, it is
easier to check.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/net/ethernet/broadcom/b44.c |   18 +++++++++---------
 drivers/net/ethernet/broadcom/b44.h |    2 +-
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 90e54d5..3c7909e 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -284,7 +284,7 @@ static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
 
 static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
 {
-	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY)
 		return 0;
 
 	return __b44_readphy(bp, bp->phy_addr, reg, val);
@@ -292,7 +292,7 @@ static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
 
 static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
 {
-	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY)
 		return 0;
 
 	return __b44_writephy(bp, bp->phy_addr, reg, val);
@@ -321,7 +321,7 @@ static int b44_phy_reset(struct b44 *bp)
 	u32 val;
 	int err;
 
-	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY)
 		return 0;
 	err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
 	if (err)
@@ -423,7 +423,7 @@ static int b44_setup_phy(struct b44 *bp)
 
 	b44_wap54g10_workaround(bp);
 
-	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY)
 		return 0;
 	if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
 		goto out;
@@ -521,7 +521,7 @@ static void b44_check_phy(struct b44 *bp)
 {
 	u32 bmsr, aux;
 
-	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
 		bp->flags |= B44_FLAG_100_BASE_T;
 		bp->flags |= B44_FLAG_FULL_DUPLEX;
 		if (!netif_carrier_ok(bp->dev)) {
@@ -1315,7 +1315,7 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind)
 	if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
 		bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL);
 		br32(bp, B44_ENET_CTRL);
-		bp->flags &= ~B44_FLAG_INTERNAL_PHY;
+		bp->flags |= B44_FLAG_EXTERNAL_PHY;
 	} else {
 		u32 val = br32(bp, B44_DEVCTRL);
 
@@ -1324,7 +1324,7 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind)
 			br32(bp, B44_DEVCTRL);
 			udelay(100);
 		}
-		bp->flags |= B44_FLAG_INTERNAL_PHY;
+		bp->flags &= ~B44_FLAG_EXTERNAL_PHY;
 	}
 }
 
@@ -1828,8 +1828,8 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 		DUPLEX_FULL : DUPLEX_HALF;
 	cmd->port = 0;
 	cmd->phy_address = bp->phy_addr;
-	cmd->transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
-		XCVR_INTERNAL : XCVR_EXTERNAL;
+	cmd->transceiver = (bp->flags & B44_FLAG_EXTERNAL_PHY) ?
+		XCVR_EXTERNAL : XCVR_INTERNAL;
 	cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
 		AUTONEG_DISABLE : AUTONEG_ENABLE;
 	if (cmd->autoneg == AUTONEG_ENABLE)
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 8993d72..8ed7d6b 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -376,7 +376,7 @@ struct b44 {
 #define B44_FLAG_ADV_10FULL	0x02000000
 #define B44_FLAG_ADV_100HALF	0x04000000
 #define B44_FLAG_ADV_100FULL	0x08000000
-#define B44_FLAG_INTERNAL_PHY	0x10000000
+#define B44_FLAG_EXTERNAL_PHY	0x10000000
 #define B44_FLAG_RX_RING_HACK	0x20000000
 #define B44_FLAG_TX_RING_HACK	0x40000000
 #define B44_FLAG_WOL_ENABLE	0x80000000
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 3/9] b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 2/9] b44: check register instead of PHY address to detect external PHY Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 4/9] b44: abort when no PHY is available at all Hauke Mehrtens
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

The PHY address 30 means there is no local PHY, but there could be an
external PHY like a switch connected via MII. This is the case on most
embedded home routers where this driver is used.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/net/ethernet/broadcom/b44.c |    2 +-
 drivers/net/ethernet/broadcom/b44.h |    6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 3c7909e..5c05d15 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2237,7 +2237,7 @@ static int b44_init_one(struct ssb_device *sdev,
 
 	/* do a phy reset to test if there is an active phy */
 	if (b44_phy_reset(bp) < 0)
-		bp->phy_addr = B44_PHY_ADDR_NO_PHY;
+		bp->phy_addr = B44_PHY_ADDR_NO_LOCAL_PHY;
 
 	netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr);
 
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 8ed7d6b..57e5357 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -280,9 +280,9 @@ struct ring_info {
 	dma_addr_t	mapping;
 };
 
-#define B44_MCAST_TABLE_SIZE	32
-#define B44_PHY_ADDR_NO_PHY	30
-#define B44_MDC_RATIO		5000000
+#define B44_MCAST_TABLE_SIZE		32
+#define B44_PHY_ADDR_NO_LOCAL_PHY	30 /* no local phy regs */
+#define B44_MDC_RATIO			5000000
 
 #define	B44_STAT_REG_DECLARE		\
 	_B44(tx_good_octets)		\
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 4/9] b44: abort when no PHY is available at all
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
                   ` (2 preceding siblings ...)
  2013-12-19  1:28 ` [PATCH v2 3/9] b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 5/9] b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii Hauke Mehrtens
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

When the phy address is 31, this means that there is no PHY connected
to this MAC at all, no internal and no external PHY. Reading these PHY
registers causes a system reset on some routers.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/net/ethernet/broadcom/b44.c |    6 ++++++
 drivers/net/ethernet/broadcom/b44.h |    1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 5c05d15..09e9e97 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2206,6 +2206,12 @@ static int b44_init_one(struct ssb_device *sdev,
 		goto err_out_powerdown;
 	}
 
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
+		dev_err(sdev->dev, "No PHY present on this MAC, aborting\n");
+		err = -ENODEV;
+		goto err_out_powerdown;
+	}
+
 	bp->mii_if.dev = dev;
 	bp->mii_if.mdio_read = b44_mii_read;
 	bp->mii_if.mdio_write = b44_mii_write;
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 57e5357..4b0c5d2 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -282,6 +282,7 @@ struct ring_info {
 
 #define B44_MCAST_TABLE_SIZE		32
 #define B44_PHY_ADDR_NO_LOCAL_PHY	30 /* no local phy regs */
+#define B44_PHY_ADDR_NO_PHY		31 /* no phy present at all */
 #define B44_MDC_RATIO			5000000
 
 #define	B44_STAT_REG_DECLARE		\
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 5/9] b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
                   ` (3 preceding siblings ...)
  2013-12-19  1:28 ` [PATCH v2 4/9] b44: abort when no PHY is available at all Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 6/9] b44: add phylib support Hauke Mehrtens
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

The next patch will add these functions for phylib, and we should
rename the old ones before. This now indicates that these functions are
used for the mdio registers and on the mii interface.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/net/ethernet/broadcom/b44.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 09e9e97..40a9de2 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -299,7 +299,7 @@ static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
 }
 
 /* miilib interface */
-static int b44_mii_read(struct net_device *dev, int phy_id, int location)
+static int b44_mdio_read_mii(struct net_device *dev, int phy_id, int location)
 {
 	u32 val;
 	struct b44 *bp = netdev_priv(dev);
@@ -309,8 +309,8 @@ static int b44_mii_read(struct net_device *dev, int phy_id, int location)
 	return val;
 }
 
-static void b44_mii_write(struct net_device *dev, int phy_id, int location,
-			 int val)
+static void b44_mdio_write_mii(struct net_device *dev, int phy_id, int location,
+			       int val)
 {
 	struct b44 *bp = netdev_priv(dev);
 	__b44_writephy(bp, phy_id, location, val);
@@ -2213,8 +2213,8 @@ static int b44_init_one(struct ssb_device *sdev,
 	}
 
 	bp->mii_if.dev = dev;
-	bp->mii_if.mdio_read = b44_mii_read;
-	bp->mii_if.mdio_write = b44_mii_write;
+	bp->mii_if.mdio_read = b44_mdio_read_mii;
+	bp->mii_if.mdio_write = b44_mdio_write_mii;
 	bp->mii_if.phy_id = bp->phy_addr;
 	bp->mii_if.phy_id_mask = 0x1f;
 	bp->mii_if.reg_num_mask = 0x1f;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 6/9] b44: add phylib support
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
                   ` (4 preceding siblings ...)
  2013-12-19  1:28 ` [PATCH v2 5/9] b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 7/9] b44: activate PHY when MAC is off Hauke Mehrtens
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

Most of the older home routers based on the Broadcom BCM47XX SoC series
are using a MAC that is supported by b44. On most of these routers not
the internal PHY of this MAC core is used, but a switch sometimes on an
external chip or integrated into the same SoC as the Ethernet core.
For this switch a special PHY driver is needed which should not be
integrated into b44 as the same switches are also used by other
Broadcom home networking SoCs which are using different Ethernet MAC
drivers. This was tested with the b53 switch driver which is currently
on its way to mainline.

If the internal PHY is not used, b44 will now search on the MDIO bus
for a phy and use the Linux phylib subsystem to register a driver.
Support for the internal PHY must stay here, because there are some
device which are suing the internal phy.

With this patch we scan the mdio bus when the sprom or nvram says that
the PHY address is 30, if a PHY was found at this address b44 uses it.

This was tested with a BCM4704, BCM4712 and BCM5354.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/net/ethernet/broadcom/Kconfig |    1 +
 drivers/net/ethernet/broadcom/b44.c   |  190 ++++++++++++++++++++++++++++++++-
 drivers/net/ethernet/broadcom/b44.h   |    3 +
 3 files changed, 189 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 2fa5b86..3f97d9f 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -23,6 +23,7 @@ config B44
 	depends on SSB_POSSIBLE && HAS_DMA
 	select SSB
 	select MII
+	select PHYLIB
 	---help---
 	  If you have a network (Ethernet) controller of this type, say Y
 	  or M and read the Ethernet-HOWTO, available from
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 40a9de2..7b1e71d 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
  * Copyright (C) 2006 Broadcom Corporation.
  * Copyright (C) 2007 Michael Buesch <m@bues.ch>
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
  *
  * Distribute under GPL.
  */
@@ -29,6 +30,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/ssb/ssb.h>
 #include <linux/slab.h>
+#include <linux/phy.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -316,6 +318,23 @@ static void b44_mdio_write_mii(struct net_device *dev, int phy_id, int location,
 	__b44_writephy(bp, phy_id, location, val);
 }
 
+static int b44_mdio_read_phylib(struct mii_bus *bus, int phy_id, int location)
+{
+	u32 val;
+	struct b44 *bp = bus->priv;
+	int rc = __b44_readphy(bp, phy_id, location, &val);
+	if (rc)
+		return 0xffffffff;
+	return val;
+}
+
+static int b44_mdio_write_phylib(struct mii_bus *bus, int phy_id, int location,
+				 u16 val)
+{
+	struct b44 *bp = bus->priv;
+	return __b44_writephy(bp, phy_id, location, val);
+}
+
 static int b44_phy_reset(struct b44 *bp)
 {
 	u32 val;
@@ -523,10 +542,12 @@ static void b44_check_phy(struct b44 *bp)
 
 	if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
 		bp->flags |= B44_FLAG_100_BASE_T;
-		bp->flags |= B44_FLAG_FULL_DUPLEX;
 		if (!netif_carrier_ok(bp->dev)) {
 			u32 val = br32(bp, B44_TX_CTRL);
-			val |= TX_CTRL_DUPLEX;
+			if (bp->flags & B44_FLAG_FULL_DUPLEX)
+				val |= TX_CTRL_DUPLEX;
+			else
+				val &= ~TX_CTRL_DUPLEX;
 			bw32(bp, B44_TX_CTRL, val);
 			netif_carrier_on(bp->dev);
 			b44_link_report(bp);
@@ -1805,6 +1826,11 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct b44 *bp = netdev_priv(dev);
 
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
+		BUG_ON(!bp->phydev);
+		return phy_ethtool_gset(bp->phydev, cmd);
+	}
+
 	cmd->supported = (SUPPORTED_Autoneg);
 	cmd->supported |= (SUPPORTED_100baseT_Half |
 			  SUPPORTED_100baseT_Full |
@@ -1846,7 +1872,23 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct b44 *bp = netdev_priv(dev);
-	u32 speed = ethtool_cmd_speed(cmd);
+	u32 speed;
+	int ret;
+
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
+		BUG_ON(!bp->phydev);
+		spin_lock_irq(&bp->lock);
+		if (netif_running(dev))
+			b44_setup_phy(bp);
+
+		ret = phy_ethtool_sset(bp->phydev, cmd);
+
+		spin_unlock_irq(&bp->lock);
+
+		return ret;
+	}
+
+	speed = ethtool_cmd_speed(cmd);
 
 	/* We do not support gigabit. */
 	if (cmd->autoneg == AUTONEG_ENABLE) {
@@ -2076,7 +2118,6 @@ static const struct ethtool_ops b44_ethtool_ops = {
 
 static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct mii_ioctl_data *data = if_mii(ifr);
 	struct b44 *bp = netdev_priv(dev);
 	int err = -EINVAL;
 
@@ -2084,7 +2125,12 @@ static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		goto out;
 
 	spin_lock_irq(&bp->lock);
-	err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
+		BUG_ON(!bp->phydev);
+		err = phy_mii_ioctl(bp->phydev, ifr, cmd);
+	} else {
+		err = generic_mii_ioctl(&bp->mii_if, if_mii(ifr), cmd, NULL);
+	}
 	spin_unlock_irq(&bp->lock);
 out:
 	return err;
@@ -2146,6 +2192,127 @@ static const struct net_device_ops b44_netdev_ops = {
 #endif
 };
 
+static void b44_adjust_link(struct net_device *dev)
+{
+	struct b44 *bp = netdev_priv(dev);
+	struct phy_device *phydev = bp->phydev;
+	bool status_changed = 0;
+
+	BUG_ON(!phydev);
+
+	if (bp->old_link != phydev->link) {
+		status_changed = 1;
+		bp->old_link = phydev->link;
+	}
+
+	/* reflect duplex change */
+	if (phydev->link) {
+		if ((phydev->duplex == DUPLEX_HALF) &&
+		    (bp->flags & B44_FLAG_FULL_DUPLEX)) {
+			status_changed = 1;
+			bp->flags &= ~B44_FLAG_FULL_DUPLEX;
+		} else if ((phydev->duplex == DUPLEX_FULL) &&
+			   !(bp->flags & B44_FLAG_FULL_DUPLEX)) {
+			status_changed = 1;
+			bp->flags |= B44_FLAG_FULL_DUPLEX;
+		}
+	}
+
+	if (status_changed) {
+		b44_check_phy(bp);
+		phy_print_status(phydev);
+	}
+}
+
+static int b44_register_phy_one(struct b44 *bp)
+{
+	struct mii_bus *mii_bus;
+	struct ssb_device *sdev = bp->sdev;
+	struct phy_device *phydev;
+	char bus_id[MII_BUS_ID_SIZE + 3];
+	int err;
+
+	mii_bus = mdiobus_alloc();
+	if (!mii_bus) {
+		dev_err(sdev->dev, "mdiobus_alloc() failed\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	mii_bus->priv = bp;
+	mii_bus->read = b44_mdio_read_phylib;
+	mii_bus->write = b44_mdio_write_phylib;
+	mii_bus->name = "b44_eth_mii";
+	mii_bus->parent = sdev->dev;
+	mii_bus->phy_mask = ~(1 << bp->phy_addr);
+	snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%x", instance);
+	mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+	if (!mii_bus->irq) {
+		dev_err(sdev->dev, "mii_bus irq allocation failed\n");
+		err = -ENOMEM;
+		goto err_out_mdiobus;
+	}
+
+	memset(mii_bus->irq, PHY_POLL, sizeof(int) * PHY_MAX_ADDR);
+
+	bp->mii_bus = mii_bus;
+
+	err = mdiobus_register(mii_bus);
+	if (err) {
+		dev_err(sdev->dev, "failed to register MII bus\n");
+		goto err_out_mdiobus_irq;
+	}
+
+	snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id, bp->phy_addr);
+
+	phydev = phy_connect(bp->dev, bus_id, &b44_adjust_link,
+			     PHY_INTERFACE_MODE_MII);
+	if (IS_ERR(phydev)) {
+		dev_err(sdev->dev, "could not attach PHY at %i\n",
+			bp->phy_addr);
+		err = PTR_ERR(phydev);
+		goto err_out_mdiobus_unregister;
+	}
+
+	/* mask with MAC supported features */
+	phydev->supported &= (SUPPORTED_100baseT_Half |
+			      SUPPORTED_100baseT_Full |
+			      SUPPORTED_Autoneg |
+			      SUPPORTED_MII);
+	phydev->advertising = phydev->supported;
+
+	bp->phydev = phydev;
+	bp->old_link = 0;
+	bp->phy_addr = phydev->addr;
+
+	dev_info(sdev->dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+		 phydev->drv->name, dev_name(&phydev->dev));
+
+	return 0;
+
+err_out_mdiobus_unregister:
+	mdiobus_unregister(mii_bus);
+
+err_out_mdiobus_irq:
+	kfree(mii_bus->irq);
+
+err_out_mdiobus:
+	mdiobus_free(mii_bus);
+
+err_out:
+	return err;
+}
+
+static void b44_unregister_phy_one(struct b44 *bp)
+{
+	struct mii_bus *mii_bus = bp->mii_bus;
+
+	phy_disconnect(bp->phydev);
+	mdiobus_unregister(mii_bus);
+	kfree(mii_bus->irq);
+	mdiobus_free(mii_bus);
+}
+
 static int b44_init_one(struct ssb_device *sdev,
 			const struct ssb_device_id *ent)
 {
@@ -2245,10 +2412,20 @@ static int b44_init_one(struct ssb_device *sdev,
 	if (b44_phy_reset(bp) < 0)
 		bp->phy_addr = B44_PHY_ADDR_NO_LOCAL_PHY;
 
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
+		err = b44_register_phy_one(bp);
+		if (err) {
+			dev_err(sdev->dev, "Cannot register PHY, aborting\n");
+			goto err_out_unregister_netdev;
+		}
+	}
+
 	netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr);
 
 	return 0;
 
+err_out_unregister_netdev:
+	unregister_netdev(dev);
 err_out_powerdown:
 	ssb_bus_may_powerdown(sdev->bus);
 
@@ -2262,8 +2439,11 @@ out:
 static void b44_remove_one(struct ssb_device *sdev)
 {
 	struct net_device *dev = ssb_get_drvdata(sdev);
+	struct b44 *bp = netdev_priv(dev);
 
 	unregister_netdev(dev);
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+		b44_unregister_phy_one(bp);
 	ssb_device_disable(sdev, 0);
 	ssb_bus_may_powerdown(sdev->bus);
 	free_netdev(dev);
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 4b0c5d2..de81639 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -397,6 +397,9 @@ struct b44 {
 	u32			tx_pending;
 	u8			phy_addr;
 	u8			force_copybreak;
+	struct phy_device	*phydev;
+	struct mii_bus		*mii_bus;
+	int			old_link;
 	struct mii_if_info	mii_if;
 };
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 7/9] b44: activate PHY when MAC is off
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
                   ` (5 preceding siblings ...)
  2013-12-19  1:28 ` [PATCH v2 6/9] b44: add phylib support Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 8/9] b44: do not set PHY address to 30 for every ext PHY Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 9/9] b44: use fixed PHY device if we do not find any Hauke Mehrtens
  8 siblings, 0 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

Without this patch we can not access the PHY when the MAC is switched
off. This PHY access is needed to configure the switch, which is done
through PHY registers.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/net/ethernet/broadcom/b44.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 7b1e71d..d17561b 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -1360,7 +1360,10 @@ static void b44_halt(struct b44 *bp)
 	bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
 	/* now reset the chip, but without enabling the MAC&PHY
 	 * part of it. This has to be done _after_ we shut down the PHY */
-	b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
+	if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+		b44_chip_reset(bp, B44_CHIP_RESET_FULL);
+	else
+		b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
 }
 
 /* bp->lock is held. */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 8/9] b44: do not set PHY address to 30 for every ext PHY
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
                   ` (6 preceding siblings ...)
  2013-12-19  1:28 ` [PATCH v2 7/9] b44: activate PHY when MAC is off Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  2013-12-19  1:28 ` [PATCH v2 9/9] b44: use fixed PHY device if we do not find any Hauke Mehrtens
  8 siblings, 0 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

b44_phy_reset() will fail for an external PHY and only work with the
internal PHY, this was an old workaround when the detection of an
external switch based on the PHY address failed and it is not needed
any more.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/net/ethernet/broadcom/b44.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index d17561b..839dd90 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -2412,8 +2412,11 @@ static int b44_init_one(struct ssb_device *sdev,
 	b44_chip_reset(bp, B44_CHIP_RESET_FULL);
 
 	/* do a phy reset to test if there is an active phy */
-	if (b44_phy_reset(bp) < 0)
-		bp->phy_addr = B44_PHY_ADDR_NO_LOCAL_PHY;
+	err = b44_phy_reset(bp);
+	if (err < 0) {
+		dev_err(sdev->dev, "phy reset failed\n");
+		goto err_out_unregister_netdev;
+	}
 
 	if (bp->flags & B44_FLAG_EXTERNAL_PHY) {
 		err = b44_register_phy_one(bp);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 9/9] b44: use fixed PHY device if we do not find any
  2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
                   ` (7 preceding siblings ...)
  2013-12-19  1:28 ` [PATCH v2 8/9] b44: do not set PHY address to 30 for every ext PHY Hauke Mehrtens
@ 2013-12-19  1:28 ` Hauke Mehrtens
  8 siblings, 0 replies; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19  1:28 UTC (permalink / raw)
  To: davem; +Cc: zambrano, netdev, f.fainelli, Hauke Mehrtens

The ADM6996L switch and some Broadcom switches with two MII interfaces
like the BCM5325F connected to two MACs on the SoC, used on some
routers do not return a valid value when reading the PHY id register
and Linux thinks there is no PHY at all, but that is wrong.
This patch registers a fixed phy in such a case and make b44 use that
instead.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 drivers/net/ethernet/broadcom/b44.c |   42 ++++++++++++++++++++++++++++++++++-
 drivers/net/ethernet/broadcom/b44.h |    3 +++
 2 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 839dd90..ea540cd 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -31,6 +31,7 @@
 #include <linux/ssb/ssb.h>
 #include <linux/slab.h>
 #include <linux/phy.h>
+#include <linux/phy_fixed.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -2233,6 +2234,11 @@ static int b44_register_phy_one(struct b44 *bp)
 	struct ssb_device *sdev = bp->sdev;
 	struct phy_device *phydev;
 	char bus_id[MII_BUS_ID_SIZE + 3];
+	struct ssb_sprom *sprom = &sdev->bus->sprom;
+	struct platform_device *pdev;
+	struct pdata_fixed_phy *pdata;
+	size_t pdata_size = sizeof(struct pdata_fixed_phy) +
+			    1 * sizeof(struct fixed_phy_conf);
 	int err;
 
 	mii_bus = mdiobus_alloc();
@@ -2266,7 +2272,41 @@ static int b44_register_phy_one(struct b44 *bp)
 		goto err_out_mdiobus_irq;
 	}
 
-	snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id, bp->phy_addr);
+	if (!bp->mii_bus->phy_map[bp->phy_addr] &&
+	    (sprom->boardflags_lo & (B44_BOARDFLAG_ROBO | B44_BOARDFLAG_ADM))) {
+
+		dev_info(sdev->dev,
+			 "could not find PHY at %i, create fixed one\n",
+			 bp->phy_addr);
+
+		pdata = kzalloc(pdata_size, GFP_KERNEL);
+		if (!pdata) {
+			dev_err(sdev->dev, "fixed phy allocation failed\n");
+			err = -ENOMEM;
+			goto err_out_mdiobus_unregister;
+		}
+		pdata->phys_num = 1;
+		pdata->name = "fixed-0";
+		pdata->phys[0].phy_id = bp->phy_addr;
+		pdata->phys[0].status.duplex = DUPLEX_FULL;
+		pdata->phys[0].status.speed = SPEED_100;
+		pdata->phys[0].status.link = 1;
+		
+		pdev = platform_device_register_data(bp->sdev->dev, "fixed-phy", 0,
+						     pdata, pdata_size);
+		kfree(pdata);
+		if (IS_ERR(pdev)) {
+			err = PTR_ERR(pdev);
+			dev_err(sdev->dev,
+			        "fixed phy registration failed with %i\n", err);
+			goto err_out_mdiobus_unregister;
+		}
+		snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, "fixed-0",
+			 bp->phy_addr);
+	} else {
+		snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id,
+			 bp->phy_addr);
+	}
 
 	phydev = phy_connect(bp->dev, bus_id, &b44_adjust_link,
 			     PHY_INTERFACE_MODE_MII);
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index de81639..3e9c3fc 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -345,6 +345,9 @@ B44_STAT_REG_DECLARE
 	struct u64_stats_sync	syncp;
 };
 
+#define	B44_BOARDFLAG_ROBO		0x0010  /* Board has robo switch */
+#define	B44_BOARDFLAG_ADM		0x0080  /* Board has ADMtek switch */
+
 struct ssb_device;
 
 struct b44 {
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver
  2013-12-19  1:28 ` [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver Hauke Mehrtens
@ 2013-12-19  1:48   ` Florian Fainelli
  2013-12-19 11:23     ` Hauke Mehrtens
  0 siblings, 1 reply; 13+ messages in thread
From: Florian Fainelli @ 2013-12-19  1:48 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: David Miller, zambrano, netdev, Vitaly Bordug, Anton Vorontsov

2013/12/18 Hauke Mehrtens <hauke@hauke-m.de>:
> This changes the fixed phy driver from registering the mdio bus when
> the module gets loaded to registering it when a device was registered.
> A phy has to get registered to this driver before it registered the
> mdio bus, but this only worked when the phys are registered in some
> arch code before the system booted completely. Now we want to do so
> when the Ethernet driver gets initialized which could be happen every
> time.
>
> To make this driver work with such a case, convert it to a platform
> driver which could be registered every time with the phys which should
> be on the bus.
>
> This was only tested on BCM47XX, but not on AR7 because I do not have
> such a device.

I do understand why you would want to do it that way, but I believe
this is should be addressed separately, outside of the actual b44
changes. Converting the fixed PHY driver into a platform driver also
has an impact on how Device Tree callers such as PowerPC would be
dealing with this.

Can you submit the required changes to arch/mips/bcm47xx/ for now and
get this change merged via David's tree? This would buy us some time
to discuss how to best deal with fixed PHY, and also take Device Tree
aware platform into account since that part has been an on-going
discussion for a while.

Thanks!

>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> CC: Florian Fainelli <florian@openwrt.org>
> CC: Vitaly Bordug <vbordug@ru.mvista.com>
> CC: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
>  arch/mips/ar7/platform.c  |   39 ++++++++++++++++++----
>  drivers/net/phy/fixed.c   |   79 ++++++++++++++++++++++-----------------------
>  include/linux/phy_fixed.h |   21 ++++++------
>  3 files changed, 83 insertions(+), 56 deletions(-)
>
> diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
> index 7e2356f..26ea35a 100644
> --- a/arch/mips/ar7/platform.c
> +++ b/arch/mips/ar7/platform.c
> @@ -251,10 +251,35 @@ static struct resource cpmac_high_res[] = {
>         },
>  };
>
> -static struct fixed_phy_status fixed_phy_status __initdata = {
> -       .link           = 1,
> -       .speed          = 100,
> -       .duplex         = 1,
> +static struct pdata_fixed_phy cpmac_phy_data = {
> +       .name           = "fixed-0",
> +       .phys_num       = 1,
> +       .phys           = {{
> +               .phy_id = 1,
> +               .irq    = PHY_POLL,
> +               .status = {
> +                       .link   = 1,
> +                       .speed  = 100,
> +                       .duplex = 1,
> +               },
> +       },
> +       {
> +               .phy_id = 1,
> +               .irq    = PHY_POLL,
> +               .status = {
> +                       .link   = 1,
> +                       .speed  = 100,
> +                       .duplex = 1,
> +               },
> +       }},
> +};
> +
> +static struct platform_device cpmac_phy = {
> +       .id             = 0,
> +       .name           = "fixed-phy",
> +       .dev = {
> +               .platform_data  = &cpmac_phy_data,
> +       },
>  };
>
>  static struct plat_cpmac_data cpmac_low_data = {
> @@ -683,7 +708,8 @@ static int __init ar7_register_devices(void)
>         }
>
>         if (ar7_has_high_cpmac()) {
> -               res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status);
> +               cpmac_phy_data.phys[1].phy_id = cpmac_high.id;
> +               cpmac_phy_data.phys_num = 2;
>                 if (!res) {
>                         cpmac_get_mac(1, cpmac_high_data.dev_addr);
>
> @@ -695,7 +721,8 @@ static int __init ar7_register_devices(void)
>         } else
>                 cpmac_low_data.phy_mask = 0xffffffff;
>
> -       res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status);
> +       cpmac_phy_data.phys[0].phy_id = cpmac_low.id;
> +       res = platform_device_register(&cpmac_phy);
>         if (!res) {
>                 cpmac_get_mac(0, cpmac_low_data.dev_addr);
>                 res = platform_device_register(&cpmac_low);
> diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
> index ba55adf..dd5154b 100644
> --- a/drivers/net/phy/fixed.c
> +++ b/drivers/net/phy/fixed.c
> @@ -5,6 +5,7 @@
>   *         Anton Vorontsov <avorontsov@ru.mvista.com>
>   *
>   * Copyright (c) 2006-2007 MontaVista Software, Inc.
> + * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
>   *
>   * This program is free software; you can redistribute  it and/or modify it
>   * under  the terms of  the GNU General  Public License as published by the
> @@ -39,11 +40,6 @@ struct fixed_phy {
>         struct list_head node;
>  };
>
> -static struct platform_device *pdev;
> -static struct fixed_mdio_bus platform_fmb = {
> -       .phys = LIST_HEAD_INIT(platform_fmb.phys),
> -};
> -
>  static int fixed_phy_update_regs(struct fixed_phy *fp)
>  {
>         u16 bmsr = BMSR_ANEGCAPABLE;
> @@ -153,7 +149,7 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
>                               int (*link_update)(struct net_device *,
>                                                  struct fixed_phy_status *))
>  {
> -       struct fixed_mdio_bus *fmb = &platform_fmb;
> +       struct fixed_mdio_bus *fmb = phydev->bus->priv;
>         struct fixed_phy *fp;
>
>         if (!link_update || !phydev || !phydev->bus)
> @@ -171,14 +167,14 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
>  }
>  EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
>
> -int fixed_phy_add(unsigned int irq, int phy_id,
> -                 struct fixed_phy_status *status)
> +static int fixed_phy_add(struct device *dev, struct fixed_mdio_bus *fmb,
> +                        unsigned int irq, int phy_id,
> +                        struct fixed_phy_status *status)
>  {
>         int ret;
> -       struct fixed_mdio_bus *fmb = &platform_fmb;
>         struct fixed_phy *fp;
>
> -       fp = kzalloc(sizeof(*fp), GFP_KERNEL);
> +       fp = devm_kzalloc(dev, sizeof(struct fixed_phy), GFP_KERNEL);
>         if (!fp)
>                 return -ENOMEM;
>
> @@ -191,36 +187,41 @@ int fixed_phy_add(unsigned int irq, int phy_id,
>
>         ret = fixed_phy_update_regs(fp);
>         if (ret)
> -               goto err_regs;
> +               return ret;
>
>         list_add_tail(&fp->node, &fmb->phys);
>
>         return 0;
> -
> -err_regs:
> -       kfree(fp);
> -       return ret;
>  }
> -EXPORT_SYMBOL_GPL(fixed_phy_add);
>
> -static int __init fixed_mdio_bus_init(void)
> +static int fixed_phy_probe(struct platform_device *pdev)
>  {
> -       struct fixed_mdio_bus *fmb = &platform_fmb;
> +       struct pdata_fixed_phy *pdata = dev_get_platdata(&pdev->dev);
> +       struct fixed_mdio_bus *fmb;
> +       struct fixed_phy_conf *phy;
>         int ret;
> +       int i;
>
> -       pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
> -       if (IS_ERR(pdev)) {
> -               ret = PTR_ERR(pdev);
> -               goto err_pdev;
> +       fmb = devm_kzalloc(&pdev->dev, sizeof(struct fixed_mdio_bus), GFP_KERNEL);
> +       if (!fmb)
> +               return -ENOMEM;
> +       INIT_LIST_HEAD(&fmb->phys);
> +       platform_set_drvdata(pdev, fmb);
> +
> +       for (i = 0; i < pdata->phys_num; i++) {
> +               phy = &pdata->phys[i];
> +               ret = fixed_phy_add(&pdev->dev, fmb, phy->irq, phy->phy_id,
> +                                   &phy->status);
> +               if (ret < 0)
> +                       return ret;
>         }
>
>         fmb->mii_bus = mdiobus_alloc();
> -       if (fmb->mii_bus == NULL) {
> -               ret = -ENOMEM;
> -               goto err_mdiobus_reg;
> +       if (!fmb->mii_bus) {
> +               return -ENOMEM;
>         }
>
> -       snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
> +       snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, pdata->name);
>         fmb->mii_bus->name = "Fixed MDIO Bus";
>         fmb->mii_bus->priv = fmb;
>         fmb->mii_bus->parent = &pdev->dev;
> @@ -236,29 +237,27 @@ static int __init fixed_mdio_bus_init(void)
>
>  err_mdiobus_alloc:
>         mdiobus_free(fmb->mii_bus);
> -err_mdiobus_reg:
> -       platform_device_unregister(pdev);
> -err_pdev:
>         return ret;
>  }
> -module_init(fixed_mdio_bus_init);
>
> -static void __exit fixed_mdio_bus_exit(void)
> +static int fixed_phy_remove(struct platform_device *pdev)
>  {
> -       struct fixed_mdio_bus *fmb = &platform_fmb;
> -       struct fixed_phy *fp, *tmp;
> +       struct fixed_mdio_bus *fmb = platform_get_drvdata(pdev);
>
>         mdiobus_unregister(fmb->mii_bus);
>         mdiobus_free(fmb->mii_bus);
> -       platform_device_unregister(pdev);
> -
> -       list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
> -               list_del(&fp->node);
> -               kfree(fp);
> -       }
> +       return 0;
>  }
> -module_exit(fixed_mdio_bus_exit);
>
> +static struct platform_driver fixed_phy_driver = {
> +       .probe = fixed_phy_probe,
> +       .remove = fixed_phy_remove,
> +       .driver = {
> +               .name = "fixed-phy",
> +       },
> +};
> +
> +module_platform_driver(fixed_phy_driver);
>  MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
>  MODULE_AUTHOR("Vitaly Bordug");
>  MODULE_LICENSE("GPL");
> diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h
> index 509d8f5..f41140e 100644
> --- a/include/linux/phy_fixed.h
> +++ b/include/linux/phy_fixed.h
> @@ -9,16 +9,17 @@ struct fixed_phy_status {
>         int asym_pause;
>  };
>
> -#ifdef CONFIG_FIXED_PHY
> -extern int fixed_phy_add(unsigned int irq, int phy_id,
> -                        struct fixed_phy_status *status);
> -#else
> -static inline int fixed_phy_add(unsigned int irq, int phy_id,
> -                               struct fixed_phy_status *status)
> -{
> -       return -ENODEV;
> -}
> -#endif /* CONFIG_FIXED_PHY */
> +struct fixed_phy_conf {
> +       int phy_id;
> +       unsigned int irq;
> +       struct fixed_phy_status status;
> +};
> +
> +struct pdata_fixed_phy {
> +       char *name;
> +       unsigned int phys_num;
> +       struct fixed_phy_conf phys[];
> +};
>
>  /*
>   * This function issued only by fixed_phy-aware drivers, no need
> --
> 1.7.10.4



-- 
Florian

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver
  2013-12-19  1:48   ` Florian Fainelli
@ 2013-12-19 11:23     ` Hauke Mehrtens
  2013-12-19 17:49       ` Florian Fainelli
  0 siblings, 1 reply; 13+ messages in thread
From: Hauke Mehrtens @ 2013-12-19 11:23 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: David Miller, zambrano, netdev, Vitaly Bordug, Anton Vorontsov

On 12/19/2013 02:48 AM, Florian Fainelli wrote:
> 2013/12/18 Hauke Mehrtens <hauke@hauke-m.de>:
>> This changes the fixed phy driver from registering the mdio bus when
>> the module gets loaded to registering it when a device was registered.
>> A phy has to get registered to this driver before it registered the
>> mdio bus, but this only worked when the phys are registered in some
>> arch code before the system booted completely. Now we want to do so
>> when the Ethernet driver gets initialized which could be happen every
>> time.
>>
>> To make this driver work with such a case, convert it to a platform
>> driver which could be registered every time with the phys which should
>> be on the bus.
>>
>> This was only tested on BCM47XX, but not on AR7 because I do not have
>> such a device.
> 
> I do understand why you would want to do it that way, but I believe
> this is should be addressed separately, outside of the actual b44
> changes. Converting the fixed PHY driver into a platform driver also
> has an impact on how Device Tree callers such as PowerPC would be
> dealing with this.

For the ADM switch we could initialize the fixed phy in the arch code,
because with that switch fixed phys are always needed, but this is also
needed for some Broadcom switches and I can not automatically detect if
that is the case. The detection could be done  based on the board the
kernel was booted on, but there are some hundreds different ones for
BCM47XX.

Sorry I missed some calls to fixed_phy_ads() in the arch code where it
is used by the device tree platforms, but that could be easily converted
to a platform device as well.

> Can you submit the required changes to arch/mips/bcm47xx/ for now and
> get this change merged via David's tree? This would buy us some time
> to discuss how to best deal with fixed PHY, and also take Device Tree
> aware platform into account since that part has been an on-going
> discussion for a while.

What changes to arch/mips/bcm47xx/ are you talking about?
Do you mean I should send the b44 patches without the fixed phy stuff
first and then we can discuss the fixed phy stuff separately, that would
be my next strategy? ;-)

> 
> Thanks!
> 
>>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>> CC: Florian Fainelli <florian@openwrt.org>
>> CC: Vitaly Bordug <vbordug@ru.mvista.com>
>> CC: Anton Vorontsov <avorontsov@ru.mvista.com>
>> ---
>>  arch/mips/ar7/platform.c  |   39 ++++++++++++++++++----
>>  drivers/net/phy/fixed.c   |   79 ++++++++++++++++++++++-----------------------
>>  include/linux/phy_fixed.h |   21 ++++++------
>>  3 files changed, 83 insertions(+), 56 deletions(-)
>>
>> diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
>> index 7e2356f..26ea35a 100644
>> --- a/arch/mips/ar7/platform.c
>> +++ b/arch/mips/ar7/platform.c
>> @@ -251,10 +251,35 @@ static struct resource cpmac_high_res[] = {
>>         },
>>  };
>>
>> -static struct fixed_phy_status fixed_phy_status __initdata = {
>> -       .link           = 1,
>> -       .speed          = 100,
>> -       .duplex         = 1,
>> +static struct pdata_fixed_phy cpmac_phy_data = {
>> +       .name           = "fixed-0",
>> +       .phys_num       = 1,
>> +       .phys           = {{
>> +               .phy_id = 1,
>> +               .irq    = PHY_POLL,
>> +               .status = {
>> +                       .link   = 1,
>> +                       .speed  = 100,
>> +                       .duplex = 1,
>> +               },
>> +       },
>> +       {
>> +               .phy_id = 1,
>> +               .irq    = PHY_POLL,
>> +               .status = {
>> +                       .link   = 1,
>> +                       .speed  = 100,
>> +                       .duplex = 1,
>> +               },
>> +       }},
>> +};
>> +
>> +static struct platform_device cpmac_phy = {
>> +       .id             = 0,
>> +       .name           = "fixed-phy",
>> +       .dev = {
>> +               .platform_data  = &cpmac_phy_data,
>> +       },
>>  };
>>
>>  static struct plat_cpmac_data cpmac_low_data = {
>> @@ -683,7 +708,8 @@ static int __init ar7_register_devices(void)
>>         }
>>
>>         if (ar7_has_high_cpmac()) {
>> -               res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status);
>> +               cpmac_phy_data.phys[1].phy_id = cpmac_high.id;
>> +               cpmac_phy_data.phys_num = 2;
>>                 if (!res) {
>>                         cpmac_get_mac(1, cpmac_high_data.dev_addr);
>>
>> @@ -695,7 +721,8 @@ static int __init ar7_register_devices(void)
>>         } else
>>                 cpmac_low_data.phy_mask = 0xffffffff;
>>
>> -       res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status);
>> +       cpmac_phy_data.phys[0].phy_id = cpmac_low.id;
>> +       res = platform_device_register(&cpmac_phy);
>>         if (!res) {
>>                 cpmac_get_mac(0, cpmac_low_data.dev_addr);
>>                 res = platform_device_register(&cpmac_low);
>> diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
>> index ba55adf..dd5154b 100644
>> --- a/drivers/net/phy/fixed.c
>> +++ b/drivers/net/phy/fixed.c
>> @@ -5,6 +5,7 @@
>>   *         Anton Vorontsov <avorontsov@ru.mvista.com>
>>   *
>>   * Copyright (c) 2006-2007 MontaVista Software, Inc.
>> + * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
>>   *
>>   * This program is free software; you can redistribute  it and/or modify it
>>   * under  the terms of  the GNU General  Public License as published by the
>> @@ -39,11 +40,6 @@ struct fixed_phy {
>>         struct list_head node;
>>  };
>>
>> -static struct platform_device *pdev;
>> -static struct fixed_mdio_bus platform_fmb = {
>> -       .phys = LIST_HEAD_INIT(platform_fmb.phys),
>> -};
>> -
>>  static int fixed_phy_update_regs(struct fixed_phy *fp)
>>  {
>>         u16 bmsr = BMSR_ANEGCAPABLE;
>> @@ -153,7 +149,7 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
>>                               int (*link_update)(struct net_device *,
>>                                                  struct fixed_phy_status *))
>>  {
>> -       struct fixed_mdio_bus *fmb = &platform_fmb;
>> +       struct fixed_mdio_bus *fmb = phydev->bus->priv;
>>         struct fixed_phy *fp;
>>
>>         if (!link_update || !phydev || !phydev->bus)
>> @@ -171,14 +167,14 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
>>  }
>>  EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
>>
>> -int fixed_phy_add(unsigned int irq, int phy_id,
>> -                 struct fixed_phy_status *status)
>> +static int fixed_phy_add(struct device *dev, struct fixed_mdio_bus *fmb,
>> +                        unsigned int irq, int phy_id,
>> +                        struct fixed_phy_status *status)
>>  {
>>         int ret;
>> -       struct fixed_mdio_bus *fmb = &platform_fmb;
>>         struct fixed_phy *fp;
>>
>> -       fp = kzalloc(sizeof(*fp), GFP_KERNEL);
>> +       fp = devm_kzalloc(dev, sizeof(struct fixed_phy), GFP_KERNEL);
>>         if (!fp)
>>                 return -ENOMEM;
>>
>> @@ -191,36 +187,41 @@ int fixed_phy_add(unsigned int irq, int phy_id,
>>
>>         ret = fixed_phy_update_regs(fp);
>>         if (ret)
>> -               goto err_regs;
>> +               return ret;
>>
>>         list_add_tail(&fp->node, &fmb->phys);
>>
>>         return 0;
>> -
>> -err_regs:
>> -       kfree(fp);
>> -       return ret;
>>  }
>> -EXPORT_SYMBOL_GPL(fixed_phy_add);
>>
>> -static int __init fixed_mdio_bus_init(void)
>> +static int fixed_phy_probe(struct platform_device *pdev)
>>  {
>> -       struct fixed_mdio_bus *fmb = &platform_fmb;
>> +       struct pdata_fixed_phy *pdata = dev_get_platdata(&pdev->dev);
>> +       struct fixed_mdio_bus *fmb;
>> +       struct fixed_phy_conf *phy;
>>         int ret;
>> +       int i;
>>
>> -       pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
>> -       if (IS_ERR(pdev)) {
>> -               ret = PTR_ERR(pdev);
>> -               goto err_pdev;
>> +       fmb = devm_kzalloc(&pdev->dev, sizeof(struct fixed_mdio_bus), GFP_KERNEL);
>> +       if (!fmb)
>> +               return -ENOMEM;
>> +       INIT_LIST_HEAD(&fmb->phys);
>> +       platform_set_drvdata(pdev, fmb);
>> +
>> +       for (i = 0; i < pdata->phys_num; i++) {
>> +               phy = &pdata->phys[i];
>> +               ret = fixed_phy_add(&pdev->dev, fmb, phy->irq, phy->phy_id,
>> +                                   &phy->status);
>> +               if (ret < 0)
>> +                       return ret;
>>         }
>>
>>         fmb->mii_bus = mdiobus_alloc();
>> -       if (fmb->mii_bus == NULL) {
>> -               ret = -ENOMEM;
>> -               goto err_mdiobus_reg;
>> +       if (!fmb->mii_bus) {
>> +               return -ENOMEM;
>>         }
>>
>> -       snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
>> +       snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, pdata->name);
>>         fmb->mii_bus->name = "Fixed MDIO Bus";
>>         fmb->mii_bus->priv = fmb;
>>         fmb->mii_bus->parent = &pdev->dev;
>> @@ -236,29 +237,27 @@ static int __init fixed_mdio_bus_init(void)
>>
>>  err_mdiobus_alloc:
>>         mdiobus_free(fmb->mii_bus);
>> -err_mdiobus_reg:
>> -       platform_device_unregister(pdev);
>> -err_pdev:
>>         return ret;
>>  }
>> -module_init(fixed_mdio_bus_init);
>>
>> -static void __exit fixed_mdio_bus_exit(void)
>> +static int fixed_phy_remove(struct platform_device *pdev)
>>  {
>> -       struct fixed_mdio_bus *fmb = &platform_fmb;
>> -       struct fixed_phy *fp, *tmp;
>> +       struct fixed_mdio_bus *fmb = platform_get_drvdata(pdev);
>>
>>         mdiobus_unregister(fmb->mii_bus);
>>         mdiobus_free(fmb->mii_bus);
>> -       platform_device_unregister(pdev);
>> -
>> -       list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
>> -               list_del(&fp->node);
>> -               kfree(fp);
>> -       }
>> +       return 0;
>>  }
>> -module_exit(fixed_mdio_bus_exit);
>>
>> +static struct platform_driver fixed_phy_driver = {
>> +       .probe = fixed_phy_probe,
>> +       .remove = fixed_phy_remove,
>> +       .driver = {
>> +               .name = "fixed-phy",
>> +       },
>> +};
>> +
>> +module_platform_driver(fixed_phy_driver);
>>  MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
>>  MODULE_AUTHOR("Vitaly Bordug");
>>  MODULE_LICENSE("GPL");
>> diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h
>> index 509d8f5..f41140e 100644
>> --- a/include/linux/phy_fixed.h
>> +++ b/include/linux/phy_fixed.h
>> @@ -9,16 +9,17 @@ struct fixed_phy_status {
>>         int asym_pause;
>>  };
>>
>> -#ifdef CONFIG_FIXED_PHY
>> -extern int fixed_phy_add(unsigned int irq, int phy_id,
>> -                        struct fixed_phy_status *status);
>> -#else
>> -static inline int fixed_phy_add(unsigned int irq, int phy_id,
>> -                               struct fixed_phy_status *status)
>> -{
>> -       return -ENODEV;
>> -}
>> -#endif /* CONFIG_FIXED_PHY */
>> +struct fixed_phy_conf {
>> +       int phy_id;
>> +       unsigned int irq;
>> +       struct fixed_phy_status status;
>> +};
>> +
>> +struct pdata_fixed_phy {
>> +       char *name;
>> +       unsigned int phys_num;
>> +       struct fixed_phy_conf phys[];
>> +};
>>
>>  /*
>>   * This function issued only by fixed_phy-aware drivers, no need
>> --
>> 1.7.10.4
> 
> 
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver
  2013-12-19 11:23     ` Hauke Mehrtens
@ 2013-12-19 17:49       ` Florian Fainelli
  0 siblings, 0 replies; 13+ messages in thread
From: Florian Fainelli @ 2013-12-19 17:49 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: David Miller, zambrano, netdev, Vitaly Bordug, Anton Vorontsov

2013/12/19 Hauke Mehrtens <hauke@hauke-m.de>:
> On 12/19/2013 02:48 AM, Florian Fainelli wrote:
>> 2013/12/18 Hauke Mehrtens <hauke@hauke-m.de>:
>>> This changes the fixed phy driver from registering the mdio bus when
>>> the module gets loaded to registering it when a device was registered.
>>> A phy has to get registered to this driver before it registered the
>>> mdio bus, but this only worked when the phys are registered in some
>>> arch code before the system booted completely. Now we want to do so
>>> when the Ethernet driver gets initialized which could be happen every
>>> time.
>>>
>>> To make this driver work with such a case, convert it to a platform
>>> driver which could be registered every time with the phys which should
>>> be on the bus.
>>>
>>> This was only tested on BCM47XX, but not on AR7 because I do not have
>>> such a device.
>>
>> I do understand why you would want to do it that way, but I believe
>> this is should be addressed separately, outside of the actual b44
>> changes. Converting the fixed PHY driver into a platform driver also
>> has an impact on how Device Tree callers such as PowerPC would be
>> dealing with this.
>
> For the ADM switch we could initialize the fixed phy in the arch code,
> because with that switch fixed phys are always needed, but this is also
> needed for some Broadcom switches and I can not automatically detect if
> that is the case. The detection could be done  based on the board the
> kernel was booted on, but there are some hundreds different ones for
> BCM47XX.

Cannot we unconditionally register a fixed PHY at address 0 and use it whether:

- we are connected to an ADM switch
- we have a dual-MAC configuration

It seems to me like this would always work, the driver is the one
deciding which MDIO bus to bind the PHY to.

>
> Sorry I missed some calls to fixed_phy_ads() in the arch code where it
> is used by the device tree platforms, but that could be easily converted
> to a platform device as well.
>
>> Can you submit the required changes to arch/mips/bcm47xx/ for now and
>> get this change merged via David's tree? This would buy us some time
>> to discuss how to best deal with fixed PHY, and also take Device Tree
>> aware platform into account since that part has been an on-going
>> discussion for a while.
>
> What changes to arch/mips/bcm47xx/ are you talking about?

I am talking about the call to fixed_phy_add() which have to happen
early enough before the fixed MDIO bus is probed, just like what AR7
does currently.

I do agree though that something needs to be done because the fixed
MDIO bus usage comes from days where it was easy to add a call to
fixed_phy_add() early enough in your platform code, this is no longer
the case with Device Tree and such.

> Do you mean I should send the b44 patches without the fixed phy stuff
> first and then we can discuss the fixed phy stuff separately, that would
> be my next strategy? ;-)
--
Florian

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2013-12-19 17:50 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-19  1:28 [PATCH v2 0/9] b44: add support for external PHY Hauke Mehrtens
2013-12-19  1:28 ` [PATCH v2 1/9] fixed-phy: register fixed PHY as platform driver Hauke Mehrtens
2013-12-19  1:48   ` Florian Fainelli
2013-12-19 11:23     ` Hauke Mehrtens
2013-12-19 17:49       ` Florian Fainelli
2013-12-19  1:28 ` [PATCH v2 2/9] b44: check register instead of PHY address to detect external PHY Hauke Mehrtens
2013-12-19  1:28 ` [PATCH v2 3/9] b44: rename B44_PHY_ADDR_NO_PHY to B44_PHY_ADDR_NO_LOCAL_PHY Hauke Mehrtens
2013-12-19  1:28 ` [PATCH v2 4/9] b44: abort when no PHY is available at all Hauke Mehrtens
2013-12-19  1:28 ` [PATCH v2 5/9] b44: rename b44_mii_{read,write} to b44_mdio_{read,write}_mii Hauke Mehrtens
2013-12-19  1:28 ` [PATCH v2 6/9] b44: add phylib support Hauke Mehrtens
2013-12-19  1:28 ` [PATCH v2 7/9] b44: activate PHY when MAC is off Hauke Mehrtens
2013-12-19  1:28 ` [PATCH v2 8/9] b44: do not set PHY address to 30 for every ext PHY Hauke Mehrtens
2013-12-19  1:28 ` [PATCH v2 9/9] b44: use fixed PHY device if we do not find any Hauke Mehrtens

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.