diff mbox

[V3,7/8] mv643xx.c: Add basic device tree support.

Message ID d2db6ddfddf90dd79c6c6c90a6006887076dea1a.1359146831.git.jason@lakedaemon.net (mailing list archive)
State New, archived
Headers show

Commit Message

Jason Cooper Jan. 25, 2013, 8:53 p.m. UTC
From: Ian Molton <ian.molton@codethink.co.uk>

    This patch adds basic device tree support to the mv643xx ethernet driver.

    It should be enough for most current users of the device, and should allow
    a painless migration.

    Signed-off-by: Ian Molton <ian.molton@codethink.co.uk>

Signed-off-by: Jason Cooper <jason@lakedaemon.net>
---
 Documentation/devicetree/bindings/net/mv643xx.txt | 75 ++++++++++++++++++
 drivers/net/ethernet/marvell/mv643xx_eth.c        | 93 +++++++++++++++++++++--
 2 files changed, 161 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/mv643xx.txt

Comments

Mark Rutland Jan. 28, 2013, 10:12 a.m. UTC | #1
Hello,

I've taken a quick look at this, and I have a couple of comments on the binding
and the way it's parsed.

On Fri, Jan 25, 2013 at 08:53:59PM +0000, Jason Cooper wrote:
> From: Ian Molton <ian.molton@codethink.co.uk>
> 
>     This patch adds basic device tree support to the mv643xx ethernet driver.
> 
>     It should be enough for most current users of the device, and should allow
>     a painless migration.
> 
>     Signed-off-by: Ian Molton <ian.molton@codethink.co.uk>
> 
> Signed-off-by: Jason Cooper <jason@lakedaemon.net>
> ---
>  Documentation/devicetree/bindings/net/mv643xx.txt | 75 ++++++++++++++++++
>  drivers/net/ethernet/marvell/mv643xx_eth.c        | 93 +++++++++++++++++++++--
>  2 files changed, 161 insertions(+), 7 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/net/mv643xx.txt
> 
> diff --git a/Documentation/devicetree/bindings/net/mv643xx.txt b/Documentation/devicetree/bindings/net/mv643xx.txt
> new file mode 100644
> index 0000000..2727f798
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/mv643xx.txt
> @@ -0,0 +1,75 @@
> +mv643xx related nodes.
> +
> +marvell,mdio-mv643xx:
> +
> +Required properties:
> +
> + - interrupts : <a> where a is the SMI interrupt number.
> + - reg : the base address and size of the controllers register space.
> +
> +Optional properties:
> + - shared_smi : on some chips, the second PHY is "shared", meaning it is
> +	really accessed via the first SMI controller. It is passed in this
> +	way due to the present structure of the driver, which requires the
> +	base address for the MAC to be passed in via the SMI controllers
> +	platform data.

The phrase "the present structure of the driver" is not something that's
generally good to hear in a binding document. Is shared_smi always going to be
required for such configurations, or is there going to be any driver rework
that makes it irrelevant?

> + - tx_csum_limit : on some devices, this option is required for proper
> +	operation wrt. jumbo frames.

This doesn't explain what this property is. Also "limit" doesn't describe
what's limited (e.g. size, rate). How about something like
max-tx-checksum-size?

> +
> +
> +Example:
> +
> +smi0: mdio@72000 {
> +	compatible = "marvell,mdio-mv643xx";
> +	reg = <0x72000 0x4000>;
> +	interrupts = <46>;
> +	tx_csum_limit = <1600>;
> +	status = "disabled";
> +};
> +
> +smi1: mdio@76000 {
> +	compatible = "marvell,mdio-mv643xx";
> +	reg = <0x76000 0x4000>;
> +	interrupts = <47>;
> +	shared_smi = <&smi0>;
> +	tx_csum_limit = <1600>;
> +	status = "disabled";
> +};
> +
> +
> +
> +marvell,mv643xx-eth:
> +
> +Required properties:
> + - interrupts : the port interrupt number.
> + - mdio : phandle of the smi device as drescribed above
> +
> +Optional properties:
> + - port_number : the port number on this bus.
> + - phy_addr : the PHY address.
> + - reg : should match the mdio reg this device is attached to.
> +	this is a required hack for now due to the way the
> +	driver is constructed. This allows the device clock to be
> +	kept running so that the MAC is not lost after boot.

More s/_/-/ candidates.

Is there any reason to have "phy_addr" rather than "phy_address"? We already
have #address-cells, which would seem to have set a precedent for naming.

[...]

> @@ -2610,6 +2613,26 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
>  	if (msp->base == NULL)
>  		goto out_free;
>  
> +	if (pdev->dev.of_node) {
> +		struct device_node *np = NULL;
> +
> +		/* when all users of this driver use FDT, we can remove this */
> +		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> +		if (!pd) {
> +			dev_dbg(&pdev->dev, "Could not allocate platform data\n");
> +			goto out_free;
> +		}
> +
> +		of_property_read_u32(pdev->dev.of_node,
> +			"tx_csum_limit", &pd->tx_csum_limit);

Is there any upper limit on what this property could be? It would be nice to
have a sanity check.

Also, of_property_read_u32 reads a u32, but pd->tx_csum_limit is an int. It
would be good to use a u32 temporary.

[...]

> @@ -2858,7 +2893,36 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
>  	struct resource *res;
>  	int err;
>  
> -	pd = pdev->dev.platform_data;
> +	if (pdev->dev.of_node) {
> +		struct device_node *np = NULL;
> +
> +		/* when all users of this driver use FDT, we can remove this */
> +		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> +		if (!pd) {
> +			dev_dbg(&pdev->dev, "Could not allocate platform data\n");
> +			return -ENOMEM;
> +		}
> +
> +		of_property_read_u32(pdev->dev.of_node,
> +			"port_number", &pd->port_number);
> +
> +		if (!of_property_read_u32(pdev->dev.of_node,
> +				"phy_addr", &pd->phy_addr))
> +			pd->phy_addr = MV643XX_ETH_PHY_ADDR(pd->phy_addr);

From a cursory glance at mv643xx_eth.c, it looks like phy_addr needs to be in
the range 0 to 0x1f. It might be worth a sanity check here (even if it just
prints a warning).

> +		else
> +			pd->phy_addr = MV643XX_ETH_PHY_ADDR_DEFAULT;
> +
> +		np = of_parse_phandle(pdev->dev.of_node, "mdio", 0);
> +		if (np) {
> +			pd->shared = of_find_device_by_node(np);
> +		} else {
> +			kfree(pd);
> +			return -ENODEV;
> +		}
> +	} else {
> +		pd = pdev->dev.platform_data;
> +	}
> +
>  	if (pd == NULL) {
>  		dev_err(&pdev->dev, "no mv643xx_eth_platform_data\n");
>  		return -ENODEV;

[...]

Thanks,
Mark.
Jason Cooper Jan. 28, 2013, 7:38 p.m. UTC | #2
On Mon, Jan 28, 2013 at 10:12:49AM +0000, Mark Rutland wrote:
> Hello,
> 
> I've taken a quick look at this, and I have a couple of comments on the binding
> and the way it's parsed.
> 
> On Fri, Jan 25, 2013 at 08:53:59PM +0000, Jason Cooper wrote:
> > From: Ian Molton <ian.molton@codethink.co.uk>
> > 
> >     This patch adds basic device tree support to the mv643xx ethernet driver.
> > 
> >     It should be enough for most current users of the device, and should allow
> >     a painless migration.
> > 
> >     Signed-off-by: Ian Molton <ian.molton@codethink.co.uk>
> > 
> > Signed-off-by: Jason Cooper <jason@lakedaemon.net>
> > ---
> >  Documentation/devicetree/bindings/net/mv643xx.txt | 75 ++++++++++++++++++
> >  drivers/net/ethernet/marvell/mv643xx_eth.c        | 93 +++++++++++++++++++++--
> >  2 files changed, 161 insertions(+), 7 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/net/mv643xx.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/net/mv643xx.txt b/Documentation/devicetree/bindings/net/mv643xx.txt
> > new file mode 100644
> > index 0000000..2727f798
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/net/mv643xx.txt
> > @@ -0,0 +1,75 @@
> > +mv643xx related nodes.
> > +
> > +marvell,mdio-mv643xx:
> > +
> > +Required properties:
> > +
> > + - interrupts : <a> where a is the SMI interrupt number.
> > + - reg : the base address and size of the controllers register space.
> > +
> > +Optional properties:
> > + - shared_smi : on some chips, the second PHY is "shared", meaning it is
> > +	really accessed via the first SMI controller. It is passed in this
> > +	way due to the present structure of the driver, which requires the
> > +	base address for the MAC to be passed in via the SMI controllers
> > +	platform data.
> 
> The phrase "the present structure of the driver" is not something that's
> generally good to hear in a binding document. Is shared_smi always going to be
> required for such configurations, or is there going to be any driver rework
> that makes it irrelevant?

Florian is working on bring mvmdio up to speed, I'll let him comment on
this.

> > + - tx_csum_limit : on some devices, this option is required for proper
> > +	operation wrt. jumbo frames.
> 
> This doesn't explain what this property is. Also "limit" doesn't describe
> what's limited (e.g. size, rate). How about something like
> max-tx-checksum-size?

sounds better, I'll update for the next version.

> 
> > +
> > +
> > +Example:
> > +
> > +smi0: mdio@72000 {
> > +	compatible = "marvell,mdio-mv643xx";
> > +	reg = <0x72000 0x4000>;
> > +	interrupts = <46>;
> > +	tx_csum_limit = <1600>;
> > +	status = "disabled";
> > +};
> > +
> > +smi1: mdio@76000 {
> > +	compatible = "marvell,mdio-mv643xx";
> > +	reg = <0x76000 0x4000>;
> > +	interrupts = <47>;
> > +	shared_smi = <&smi0>;
> > +	tx_csum_limit = <1600>;
> > +	status = "disabled";
> > +};
> > +
> > +
> > +
> > +marvell,mv643xx-eth:
> > +
> > +Required properties:
> > + - interrupts : the port interrupt number.
> > + - mdio : phandle of the smi device as drescribed above
> > +
> > +Optional properties:
> > + - port_number : the port number on this bus.
> > + - phy_addr : the PHY address.
> > + - reg : should match the mdio reg this device is attached to.
> > +	this is a required hack for now due to the way the
> > +	driver is constructed. This allows the device clock to be
> > +	kept running so that the MAC is not lost after boot.
> 
> More s/_/-/ candidates.

ok.

> Is there any reason to have "phy_addr" rather than "phy_address"? We already
> have #address-cells, which would seem to have set a precedent for naming.

Well, we also have "reg", which would seem to indicate the opposite.  And,
following your logic, we should really say "physical_address" :-P .  I
personally feel "phy_addr" is well understood, but I don't have a strong
opinion on it.

> 
> [...]
> 
> > @@ -2610,6 +2613,26 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
> >  	if (msp->base == NULL)
> >  		goto out_free;
> >  
> > +	if (pdev->dev.of_node) {
> > +		struct device_node *np = NULL;
> > +
> > +		/* when all users of this driver use FDT, we can remove this */
> > +		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> > +		if (!pd) {
> > +			dev_dbg(&pdev->dev, "Could not allocate platform data\n");
> > +			goto out_free;
> > +		}
> > +
> > +		of_property_read_u32(pdev->dev.of_node,
> > +			"tx_csum_limit", &pd->tx_csum_limit);
> 
> Is there any upper limit on what this property could be? It would be nice to
> have a sanity check.
> 
> Also, of_property_read_u32 reads a u32, but pd->tx_csum_limit is an int. It
> would be good to use a u32 temporary.

Good catch, I'll update for both.

> 
> [...]
> 
> > @@ -2858,7 +2893,36 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
> >  	struct resource *res;
> >  	int err;
> >  
> > -	pd = pdev->dev.platform_data;
> > +	if (pdev->dev.of_node) {
> > +		struct device_node *np = NULL;
> > +
> > +		/* when all users of this driver use FDT, we can remove this */
> > +		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> > +		if (!pd) {
> > +			dev_dbg(&pdev->dev, "Could not allocate platform data\n");
> > +			return -ENOMEM;
> > +		}
> > +
> > +		of_property_read_u32(pdev->dev.of_node,
> > +			"port_number", &pd->port_number);
> > +
> > +		if (!of_property_read_u32(pdev->dev.of_node,
> > +				"phy_addr", &pd->phy_addr))
> > +			pd->phy_addr = MV643XX_ETH_PHY_ADDR(pd->phy_addr);
> 
> From a cursory glance at mv643xx_eth.c, it looks like phy_addr needs to be in
> the range 0 to 0x1f. It might be worth a sanity check here (even if it just
> prints a warning).

right, this had been commented elsewhere.  phy_addr is XORd with 0x80,
so I'll correct my subsequent patch adding the DT entries and add the
warning here.

Thanks for the review,

Jason.
Ian Molton Jan. 29, 2013, 10:26 a.m. UTC | #3
On 28/01/13 19:38, Jason Cooper wrote:

Good to see this patch get some TLC guys - have at it :)

-Ian
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/net/mv643xx.txt b/Documentation/devicetree/bindings/net/mv643xx.txt
new file mode 100644
index 0000000..2727f798
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/mv643xx.txt
@@ -0,0 +1,75 @@ 
+mv643xx related nodes.
+
+marvell,mdio-mv643xx:
+
+Required properties:
+
+ - interrupts : <a> where a is the SMI interrupt number.
+ - reg : the base address and size of the controllers register space.
+
+Optional properties:
+ - shared_smi : on some chips, the second PHY is "shared", meaning it is
+	really accessed via the first SMI controller. It is passed in this
+	way due to the present structure of the driver, which requires the
+	base address for the MAC to be passed in via the SMI controllers
+	platform data.
+ - tx_csum_limit : on some devices, this option is required for proper
+	operation wrt. jumbo frames.
+
+
+Example:
+
+smi0: mdio@72000 {
+	compatible = "marvell,mdio-mv643xx";
+	reg = <0x72000 0x4000>;
+	interrupts = <46>;
+	tx_csum_limit = <1600>;
+	status = "disabled";
+};
+
+smi1: mdio@76000 {
+	compatible = "marvell,mdio-mv643xx";
+	reg = <0x76000 0x4000>;
+	interrupts = <47>;
+	shared_smi = <&smi0>;
+	tx_csum_limit = <1600>;
+	status = "disabled";
+};
+
+
+
+marvell,mv643xx-eth:
+
+Required properties:
+ - interrupts : the port interrupt number.
+ - mdio : phandle of the smi device as drescribed above
+
+Optional properties:
+ - port_number : the port number on this bus.
+ - phy_addr : the PHY address.
+ - reg : should match the mdio reg this device is attached to.
+	this is a required hack for now due to the way the
+	driver is constructed. This allows the device clock to be
+	kept running so that the MAC is not lost after boot.
+
+
+Example:
+
+egiga0 {
+	compatible = "marvell,mv643xx-eth";
+	reg = <0x72000 0x4000>;
+	mdio = <&smi0>;
+	port_number = <0>;
+	phy_addr = <0x80>;
+	interrupts = <11>;
+};
+
+egiga1 {
+	compatible = "marvell,mv643xx-eth";
+	reg = <0x76000 0x4000>;
+	mdio = <&smi1>;
+	port_number = <0>;
+	phy_addr = <0x81>;
+	interrupts = <15>;
+};
+
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 84c1326..7048d7c 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -48,6 +48,9 @@ 
 #include <linux/ethtool.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
@@ -2586,7 +2589,7 @@  static void infer_hw_params(struct mv643xx_eth_shared_private *msp)
 static int mv643xx_eth_shared_probe(struct platform_device *pdev)
 {
 	static int mv643xx_eth_version_printed;
-	struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
+	struct mv643xx_eth_shared_platform_data *pd;
 	struct mv643xx_eth_shared_private *msp;
 	const struct mbus_dram_target_info *dram;
 	struct resource *res;
@@ -2610,6 +2613,26 @@  static int mv643xx_eth_shared_probe(struct platform_device *pdev)
 	if (msp->base == NULL)
 		goto out_free;
 
+	if (pdev->dev.of_node) {
+		struct device_node *np = NULL;
+
+		/* when all users of this driver use FDT, we can remove this */
+		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+		if (!pd) {
+			dev_dbg(&pdev->dev, "Could not allocate platform data\n");
+			goto out_free;
+		}
+
+		of_property_read_u32(pdev->dev.of_node,
+			"tx_csum_limit", &pd->tx_csum_limit);
+
+		np = of_parse_phandle(pdev->dev.of_node, "shared_smi", 0);
+		if (np)
+			pd->shared_smi = of_find_device_by_node(np);
+
+	} else {
+		pd = pdev->dev.platform_data;
+	}
 	/*
 	 * Set up and register SMI bus.
 	 */
@@ -2642,7 +2665,6 @@  static int mv643xx_eth_shared_probe(struct platform_device *pdev)
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (res != NULL) {
 		int err;
-
 		err = request_irq(res->start, mv643xx_eth_err_irq,
 				  IRQF_SHARED, "mv643xx_eth", msp);
 		if (!err) {
@@ -2660,6 +2682,10 @@  static int mv643xx_eth_shared_probe(struct platform_device *pdev)
 
 	msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
 					pd->tx_csum_limit : 9 * 1024;
+
+	if (pdev->dev.of_node)
+		kfree(pd);  /* If we created a fake pd, free it now */
+
 	infer_hw_params(msp);
 
 	platform_set_drvdata(pdev, msp);
@@ -2693,12 +2719,21 @@  static int mv643xx_eth_shared_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id mv_mdio_dt_ids[] __devinitdata = {
+	{ .compatible = "marvell,mdio-mv643xx", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mv_mdio_dt_ids);
+#endif
+
 static struct platform_driver mv643xx_eth_shared_driver = {
 	.probe		= mv643xx_eth_shared_probe,
 	.remove		= mv643xx_eth_shared_remove,
 	.driver = {
 		.name	= MV643XX_ETH_SHARED_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(mv_mdio_dt_ids),
 	},
 };
 
@@ -2858,7 +2893,36 @@  static int mv643xx_eth_probe(struct platform_device *pdev)
 	struct resource *res;
 	int err;
 
-	pd = pdev->dev.platform_data;
+	if (pdev->dev.of_node) {
+		struct device_node *np = NULL;
+
+		/* when all users of this driver use FDT, we can remove this */
+		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+		if (!pd) {
+			dev_dbg(&pdev->dev, "Could not allocate platform data\n");
+			return -ENOMEM;
+		}
+
+		of_property_read_u32(pdev->dev.of_node,
+			"port_number", &pd->port_number);
+
+		if (!of_property_read_u32(pdev->dev.of_node,
+				"phy_addr", &pd->phy_addr))
+			pd->phy_addr = MV643XX_ETH_PHY_ADDR(pd->phy_addr);
+		else
+			pd->phy_addr = MV643XX_ETH_PHY_ADDR_DEFAULT;
+
+		np = of_parse_phandle(pdev->dev.of_node, "mdio", 0);
+		if (np) {
+			pd->shared = of_find_device_by_node(np);
+		} else {
+			kfree(pd);
+			return -ENODEV;
+		}
+	} else {
+		pd = pdev->dev.platform_data;
+	}
+
 	if (pd == NULL) {
 		dev_err(&pdev->dev, "no mv643xx_eth_platform_data\n");
 		return -ENODEV;
@@ -2866,12 +2930,15 @@  static int mv643xx_eth_probe(struct platform_device *pdev)
 
 	if (pd->shared == NULL) {
 		dev_err(&pdev->dev, "no mv643xx_eth_platform_data->shared\n");
-		return -ENODEV;
+		err = -ENODEV;
+		goto out_free_pd;
 	}
 
 	dev = alloc_etherdev_mq(sizeof(struct mv643xx_eth_private), 8);
-	if (!dev)
-		return -ENOMEM;
+	if (!dev) {
+		err = -ENOMEM;
+		goto out_free_pd;
+	}
 
 	mp = netdev_priv(dev);
 	platform_set_drvdata(pdev, mp);
@@ -2908,6 +2975,8 @@  static int mv643xx_eth_probe(struct platform_device *pdev)
 
 	init_pscr(mp, pd->speed, pd->duplex);
 
+	if (pdev->dev.of_node)
+		kfree(pd); /* If we created a fake pd, free it now */
 
 	mib_counters_clear(mp);
 
@@ -2927,7 +2996,6 @@  static int mv643xx_eth_probe(struct platform_device *pdev)
 	mp->rx_oom.data = (unsigned long)mp;
 	mp->rx_oom.function = oom_timer_wrapper;
 
-
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	BUG_ON(!res);
 	dev->irq = res->start;
@@ -2976,6 +3044,8 @@  out:
 	}
 #endif
 	free_netdev(dev);
+out_free_pd:
+	kfree(pd);
 
 	return err;
 }
@@ -3015,6 +3085,14 @@  static void mv643xx_eth_shutdown(struct platform_device *pdev)
 		port_reset(mp);
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id mv_eth_dt_ids[] __devinitdata = {
+	{ .compatible = "marvell,mv643xx-eth", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mv_eth_dt_ids);
+#endif
+
 static struct platform_driver mv643xx_eth_driver = {
 	.probe		= mv643xx_eth_probe,
 	.remove		= mv643xx_eth_remove,
@@ -3022,6 +3100,7 @@  static struct platform_driver mv643xx_eth_driver = {
 	.driver = {
 		.name	= MV643XX_ETH_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(mv_eth_dt_ids),
 	},
 };