diff mbox

ARM: imx6: init enet MAC address

Message ID 1400566266-22746-1-git-send-email-b38611@freescale.com
State New
Headers show

Commit Message

Nimrod Andy May 20, 2014, 6:11 a.m. UTC
Enet get MAC address order:
>From module parameters or kernel command line -> device tree ->
pfuse -> mac registers set by bootloader -> random mac address.

When there have no "fec.macaddr" parameters set in kernel command
line, enet driver get MAC address from device tree. And then if
the MAC address set in device tree and is valid, enet driver get
MAC address from device tree. Otherwise, enet get MAC address from
pfuse. So, in the condition, update the MAC address (read from pfuse)
to device tree.

Signed-off-by: Fugang Duan <B38611@freescale.com>
---
 arch/arm/mach-imx/common.h      |    1 +
 arch/arm/mach-imx/mach-imx6q.c  |   90 ++++++++++++++++++++++++++++++++++++++-
 arch/arm/mach-imx/mach-imx6sl.c |    8 +++-
 3 files changed, 96 insertions(+), 3 deletions(-)

Comments

Sascha Hauer May 20, 2014, 9:03 a.m. UTC | #1
On Tue, May 20, 2014 at 02:11:06PM +0800, Fugang Duan wrote:
> Enet get MAC address order:
> From module parameters or kernel command line -> device tree ->
> pfuse -> mac registers set by bootloader -> random mac address.
> 
> When there have no "fec.macaddr" parameters set in kernel command
> line, enet driver get MAC address from device tree. And then if
> the MAC address set in device tree and is valid, enet driver get
> MAC address from device tree. Otherwise, enet get MAC address from
> pfuse. So, in the condition, update the MAC address (read from pfuse)
> to device tree.
> 
> +#define OCOTP_MACn(n)		(0x00000620 + (n) * 0x10)
> +#define IMX_MAX_ENET_NUM	2
> +void __init imx6_enet_mac_init(const char *compatible)

static

> +{
> +	struct device_node *ocotp_np, *enet_np, *from = NULL;
> +	void __iomem *base;
> +	struct property *newmac;
> +	u32 macaddr0_low;
> +	u32 macaddr0_high = 0;
> +	u32 macaddr1_high = 0;
> +	u8 *macaddr;
> +	int i;
> +
> +	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
> +		enet_np = of_find_compatible_node(from, NULL, compatible);
> +		if (!enet_np)
> +			return;
> +
> +		from = enet_np;
> +
> +		if (of_get_mac_address(enet_np))
> +			goto put_enet_node;
> +
> +		ocotp_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
> +		if (!ocotp_np) {
> +			pr_warn("failed to find ocotp node\n");
> +			goto put_enet_node;
> +		}
> +
> +		base = of_iomap(ocotp_np, 0);
> +		if (!base) {
> +			pr_warn("failed to map ocotp\n");
> +			goto put_ocotp_node;
> +		}

Move this outside the loop.

> +
> +		macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
> +		if (i)
> +			macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
> +		else
> +			macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));

You go over these register reads two times and read the very same
registers two times. Argh! Could please look at your code before posting
it?

> +
> +		newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
> +		if (!newmac)
> +			goto put_ocotp_node;
> +
> +		newmac->value = newmac + 1;
> +		newmac->length = 6;
> +		newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
> +		if (!newmac->name) {
> +			kfree(newmac);
> +			goto put_ocotp_node;
> +		}
> +
> +		macaddr = newmac->value;
> +		if (i) {
> +			macaddr[0] = (macaddr1_high >> 24) & 0xff;
> +			macaddr[1] = (macaddr1_high >> 16) & 0xff;
> +			macaddr[2] = (macaddr1_high >> 8) & 0xff;
> +			macaddr[3] = macaddr1_high & 0xff;
> +			macaddr[4] = (macaddr0_low >> 24) & 0xff;
> +			macaddr[5] = (macaddr0_low >> 16) & 0xff;
> +		} else {
> +			macaddr[0] = (macaddr0_low >> 8) & 0xff;
> +			macaddr[1] = macaddr0_low & 0xff;
> +			macaddr[2] = (macaddr0_high >> 24) & 0xff;
> +			macaddr[3] = (macaddr0_high >> 16) & 0xff;
> +			macaddr[4] = (macaddr0_high >> 8) & 0xff;
> +			macaddr[5] = macaddr0_high & 0xff;
> +		}

It makes no sense to have a IMX_MAX_ENET_NUM define when the code
assumes that the only valid value is 2.

All this is probably far more readable and less fishy when you move the
fixup of a single enet device to a extra function which you call from
the loop.

Sascha
Fugang Duan May 20, 2014, 9:24 a.m. UTC | #2
From: Sascha Hauer <s.hauer@pengutronix.de>
Data: Tuesday, May 20, 2014 5:03 PM

>To: Duan Fugang-B38611
>Cc: Li Frank-B20596; Guo Shawn-R65073; linux-arm-
>kernel@lists.infradead.org; kernel@pengutronix.de
>Subject: Re: [PATCH] ARM: imx6: init enet MAC address
>
>On Tue, May 20, 2014 at 02:11:06PM +0800, Fugang Duan wrote:
>> Enet get MAC address order:
>> From module parameters or kernel command line -> device tree -> pfuse
>> -> mac registers set by bootloader -> random mac address.
>>
>> When there have no "fec.macaddr" parameters set in kernel command
>> line, enet driver get MAC address from device tree. And then if the
>> MAC address set in device tree and is valid, enet driver get MAC
>> address from device tree. Otherwise, enet get MAC address from pfuse.
>> So, in the condition, update the MAC address (read from pfuse) to
>> device tree.
>>
>> +#define OCOTP_MACn(n)		(0x00000620 + (n) * 0x10)
>> +#define IMX_MAX_ENET_NUM	2
>> +void __init imx6_enet_mac_init(const char *compatible)
>
>static
>
The .fun() will be called for imx6sl, imx6sx(the latest chip) machine files.

>> +{
>> +	struct device_node *ocotp_np, *enet_np, *from = NULL;
>> +	void __iomem *base;
>> +	struct property *newmac;
>> +	u32 macaddr0_low;
>> +	u32 macaddr0_high = 0;
>> +	u32 macaddr1_high = 0;
>> +	u8 *macaddr;
>> +	int i;
>> +
>> +	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
>> +		enet_np = of_find_compatible_node(from, NULL, compatible);
>> +		if (!enet_np)
>> +			return;
>> +
>> +		from = enet_np;
>> +
>> +		if (of_get_mac_address(enet_np))
>> +			goto put_enet_node;
>> +
>> +		ocotp_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-
>ocotp");
>> +		if (!ocotp_np) {
>> +			pr_warn("failed to find ocotp node\n");
>> +			goto put_enet_node;
>> +		}
>> +
>> +		base = of_iomap(ocotp_np, 0);
>> +		if (!base) {
>> +			pr_warn("failed to map ocotp\n");
>> +			goto put_ocotp_node;
>> +		}
>
>Move this outside the loop.
>
Agree, I will move the ocotp node from the loop. 

>> +
>> +		macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
>> +		if (i)
>> +			macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
>> +		else
>> +			macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));
>
>You go over these register reads two times and read the very same
>registers two times. Argh! Could please look at your code before posting
>it?
>
For some other platform like imx6sx has two enet MACs, so "i" is 0, 1.
You means OCOTP_MACn(1) is read twice, I will change it. Thanks.

>> +
>> +		newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
>> +		if (!newmac)
>> +			goto put_ocotp_node;
>> +
>> +		newmac->value = newmac + 1;
>> +		newmac->length = 6;
>> +		newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
>> +		if (!newmac->name) {
>> +			kfree(newmac);
>> +			goto put_ocotp_node;
>> +		}
>> +
>> +		macaddr = newmac->value;
>> +		if (i) {
>> +			macaddr[0] = (macaddr1_high >> 24) & 0xff;
>> +			macaddr[1] = (macaddr1_high >> 16) & 0xff;
>> +			macaddr[2] = (macaddr1_high >> 8) & 0xff;
>> +			macaddr[3] = macaddr1_high & 0xff;
>> +			macaddr[4] = (macaddr0_low >> 24) & 0xff;
>> +			macaddr[5] = (macaddr0_low >> 16) & 0xff;
>> +		} else {
>> +			macaddr[0] = (macaddr0_low >> 8) & 0xff;
>> +			macaddr[1] = macaddr0_low & 0xff;
>> +			macaddr[2] = (macaddr0_high >> 24) & 0xff;
>> +			macaddr[3] = (macaddr0_high >> 16) & 0xff;
>> +			macaddr[4] = (macaddr0_high >> 8) & 0xff;
>> +			macaddr[5] = macaddr0_high & 0xff;
>> +		}
>
>It makes no sense to have a IMX_MAX_ENET_NUM define when the code assumes
>that the only valid value is 2.
>
You mean remove the "IMX_MAX_ENET_NUM" ?

>All this is probably far more readable and less fishy when you move the
>fixup of a single enet device to a extra function which you call from the
>loop.
>
Because imx6sx has two enet MACs, and the function is called for imx6qdl/imx6sl/imx6sx, so add the loop in here.
For imx6qdl/imx6sl, there just have one MAC, the second loop don't go through the flow. 
Do you have other suggestion ?

Thanks!
Sascha Hauer May 20, 2014, 9:57 a.m. UTC | #3
On Tue, May 20, 2014 at 09:24:01AM +0000, fugang.duan@freescale.com wrote:
> From: Sascha Hauer <s.hauer@pengutronix.de>
> Data: Tuesday, May 20, 2014 5:03 PM
> 
> >To: Duan Fugang-B38611
> >Cc: Li Frank-B20596; Guo Shawn-R65073; linux-arm-
> >kernel@lists.infradead.org; kernel@pengutronix.de
> >Subject: Re: [PATCH] ARM: imx6: init enet MAC address
> >
> >On Tue, May 20, 2014 at 02:11:06PM +0800, Fugang Duan wrote:
> >> Enet get MAC address order:
> >> From module parameters or kernel command line -> device tree -> pfuse
> >> -> mac registers set by bootloader -> random mac address.
> >>
> >> When there have no "fec.macaddr" parameters set in kernel command
> >> line, enet driver get MAC address from device tree. And then if the
> >> MAC address set in device tree and is valid, enet driver get MAC
> >> address from device tree. Otherwise, enet get MAC address from pfuse.
> >> So, in the condition, update the MAC address (read from pfuse) to
> >> device tree.
> >>
> >> +#define OCOTP_MACn(n)		(0x00000620 + (n) * 0x10)
> >> +#define IMX_MAX_ENET_NUM	2
> >> +void __init imx6_enet_mac_init(const char *compatible)
> >
> >static
> >
> The .fun() will be called for imx6sl, imx6sx(the latest chip) machine files.
> 
> >> +{
> >> +	struct device_node *ocotp_np, *enet_np, *from = NULL;
> >> +	void __iomem *base;
> >> +	struct property *newmac;
> >> +	u32 macaddr0_low;
> >> +	u32 macaddr0_high = 0;
> >> +	u32 macaddr1_high = 0;
> >> +	u8 *macaddr;
> >> +	int i;
> >> +
> >> +	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
> >> +		enet_np = of_find_compatible_node(from, NULL, compatible);
> >> +		if (!enet_np)
> >> +			return;
> >> +
> >> +		from = enet_np;
> >> +
> >> +		if (of_get_mac_address(enet_np))
> >> +			goto put_enet_node;
> >> +
> >> +		ocotp_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-
> >ocotp");
> >> +		if (!ocotp_np) {
> >> +			pr_warn("failed to find ocotp node\n");
> >> +			goto put_enet_node;
> >> +		}
> >> +
> >> +		base = of_iomap(ocotp_np, 0);
> >> +		if (!base) {
> >> +			pr_warn("failed to map ocotp\n");
> >> +			goto put_ocotp_node;
> >> +		}
> >
> >Move this outside the loop.
> >
> Agree, I will move the ocotp node from the loop. 
> 
> >> +
> >> +		macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
> >> +		if (i)
> >> +			macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
> >> +		else
> >> +			macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));
> >
> >You go over these register reads two times and read the very same
> >registers two times. Argh! Could please look at your code before posting
> >it?
> >
> For some other platform like imx6sx has two enet MACs, so "i" is 0, 1.
> You means OCOTP_MACn(1) is read twice, I will change it. Thanks.

What you do is:

	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
		...
		macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
		if (i)
			macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
		else
			macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));
		...
	}

What you should do is:

	macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
	macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
	macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));

	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
		...
	}
> 
> >> +
> >> +		newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
> >> +		if (!newmac)
> >> +			goto put_ocotp_node;
> >> +
> >> +		newmac->value = newmac + 1;
> >> +		newmac->length = 6;
> >> +		newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
> >> +		if (!newmac->name) {
> >> +			kfree(newmac);
> >> +			goto put_ocotp_node;
> >> +		}
> >> +
> >> +		macaddr = newmac->value;
> >> +		if (i) {
> >> +			macaddr[0] = (macaddr1_high >> 24) & 0xff;
> >> +			macaddr[1] = (macaddr1_high >> 16) & 0xff;
> >> +			macaddr[2] = (macaddr1_high >> 8) & 0xff;
> >> +			macaddr[3] = macaddr1_high & 0xff;
> >> +			macaddr[4] = (macaddr0_low >> 24) & 0xff;
> >> +			macaddr[5] = (macaddr0_low >> 16) & 0xff;
> >> +		} else {
> >> +			macaddr[0] = (macaddr0_low >> 8) & 0xff;
> >> +			macaddr[1] = macaddr0_low & 0xff;
> >> +			macaddr[2] = (macaddr0_high >> 24) & 0xff;
> >> +			macaddr[3] = (macaddr0_high >> 16) & 0xff;
> >> +			macaddr[4] = (macaddr0_high >> 8) & 0xff;
> >> +			macaddr[5] = macaddr0_high & 0xff;
> >> +		}
> >
> >It makes no sense to have a IMX_MAX_ENET_NUM define when the code assumes
> >that the only valid value is 2.
> >
> You mean remove the "IMX_MAX_ENET_NUM" ?
> 
> >All this is probably far more readable and less fishy when you move the
> >fixup of a single enet device to a extra function which you call from the
> >loop.
> >
> Because imx6sx has two enet MACs, and the function is called for imx6qdl/imx6sl/imx6sx, so add the loop in here.
> For imx6qdl/imx6sl, there just have one MAC, the second loop don't go through the flow. 
> Do you have other suggestion ?

What I want to say is: When you have a loop and the loop body gets to
complicated, then it often improves readability to move the loop body to
an extra function, like this:

static int imx6_enet_mac_init_one(struct device_node *enet, const u8 *mac)
{
	struct property *newmac;
	u8 mac[6];

	if (of_get_mac_address(enet))
		return 0;

	newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
	if (!newmac)
		return -ENOMEM;

	newmac->length = 6;
	newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
	newmac->value = kmemdup(mac, 6, GFP_KERNEL);

	of_update_property(enet_np, newmac);

	release_stuff();
}

int imx6_enet_mac_init(const char *compatible)
{
	struct device_node *from = NULL;
	u8 mac[6];

	macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
	macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
	macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));

	mac[0] = ...;

	enet_np = of_find_compatible_node(NULL, NULL, compatible);
	if (!enet_np)
		return 0;

	imx6_enet_mac_init_one(enet_np, mac);

	enet_np = of_find_compatible_node(enet_np, NULL, compatible);
	if (!enet_np)
		return 0;

	mac[0] = ...;

	imx6_enet_mac_init_one(enet_no, mac);
}

(here I removed the loop which makes the code even more straight
forward)

Sascha
Fugang Duan May 20, 2014, 10:23 a.m. UTC | #4
From: Sascha Hauer <s.hauer@pengutronix.de>
Data: Tuesday, May 20, 2014 5:57 PM

>To: Duan Fugang-B38611
>Cc: Li Frank-B20596; Guo Shawn-R65073; linux-arm-
>kernel@lists.infradead.org; kernel@pengutronix.de
>Subject: Re: [PATCH] ARM: imx6: init enet MAC address
>
>On Tue, May 20, 2014 at 09:24:01AM +0000, fugang.duan@freescale.com wrote:
>> From: Sascha Hauer <s.hauer@pengutronix.de>
>> Data: Tuesday, May 20, 2014 5:03 PM
>>
>> >To: Duan Fugang-B38611
>> >Cc: Li Frank-B20596; Guo Shawn-R65073; linux-arm-
>> >kernel@lists.infradead.org; kernel@pengutronix.de
>> >Subject: Re: [PATCH] ARM: imx6: init enet MAC address
>> >
>> >On Tue, May 20, 2014 at 02:11:06PM +0800, Fugang Duan wrote:
>> >> Enet get MAC address order:
>> >> From module parameters or kernel command line -> device tree ->
>> >> pfuse
>> >> -> mac registers set by bootloader -> random mac address.
>> >>
>> >> When there have no "fec.macaddr" parameters set in kernel command
>> >> line, enet driver get MAC address from device tree. And then if the
>> >> MAC address set in device tree and is valid, enet driver get MAC
>> >> address from device tree. Otherwise, enet get MAC address from pfuse.
>> >> So, in the condition, update the MAC address (read from pfuse) to
>> >> device tree.
>> >>
>> >> +#define OCOTP_MACn(n)		(0x00000620 + (n) * 0x10)
>> >> +#define IMX_MAX_ENET_NUM	2
>> >> +void __init imx6_enet_mac_init(const char *compatible)
>> >
>> >static
>> >
>> The .fun() will be called for imx6sl, imx6sx(the latest chip) machine
>files.
>>
>> >> +{
>> >> +	struct device_node *ocotp_np, *enet_np, *from = NULL;
>> >> +	void __iomem *base;
>> >> +	struct property *newmac;
>> >> +	u32 macaddr0_low;
>> >> +	u32 macaddr0_high = 0;
>> >> +	u32 macaddr1_high = 0;
>> >> +	u8 *macaddr;
>> >> +	int i;
>> >> +
>> >> +	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
>> >> +		enet_np = of_find_compatible_node(from, NULL,
>compatible);
>> >> +		if (!enet_np)
>> >> +			return;
>> >> +
>> >> +		from = enet_np;
>> >> +
>> >> +		if (of_get_mac_address(enet_np))
>> >> +			goto put_enet_node;
>> >> +
>> >> +		ocotp_np = of_find_compatible_node(NULL, NULL,
>"fsl,imx6q-
>> >ocotp");
>> >> +		if (!ocotp_np) {
>> >> +			pr_warn("failed to find ocotp node\n");
>> >> +			goto put_enet_node;
>> >> +		}
>> >> +
>> >> +		base = of_iomap(ocotp_np, 0);
>> >> +		if (!base) {
>> >> +			pr_warn("failed to map ocotp\n");
>> >> +			goto put_ocotp_node;
>> >> +		}
>> >
>> >Move this outside the loop.
>> >
>> Agree, I will move the ocotp node from the loop.
>>
>> >> +
>> >> +		macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
>> >> +		if (i)
>> >> +			macaddr1_high = readl_relaxed(base +
>OCOTP_MACn(2));
>> >> +		else
>> >> +			macaddr0_high = readl_relaxed(base +
>OCOTP_MACn(0));
>> >
>> >You go over these register reads two times and read the very same
>> >registers two times. Argh! Could please look at your code before
>> >posting it?
>> >
>> For some other platform like imx6sx has two enet MACs, so "i" is 0, 1.
>> You means OCOTP_MACn(1) is read twice, I will change it. Thanks.
>
>What you do is:
>
>	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
>		...
>		macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
>		if (i)
>			macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
>		else
>			macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));
>		...
>	}
>
>What you should do is:
>
>	macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
>	macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
>	macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));
>
>	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
>		...
>	}
>>
>> >> +
>> >> +		newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
>> >> +		if (!newmac)
>> >> +			goto put_ocotp_node;
>> >> +
>> >> +		newmac->value = newmac + 1;
>> >> +		newmac->length = 6;
>> >> +		newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
>> >> +		if (!newmac->name) {
>> >> +			kfree(newmac);
>> >> +			goto put_ocotp_node;
>> >> +		}
>> >> +
>> >> +		macaddr = newmac->value;
>> >> +		if (i) {
>> >> +			macaddr[0] = (macaddr1_high >> 24) & 0xff;
>> >> +			macaddr[1] = (macaddr1_high >> 16) & 0xff;
>> >> +			macaddr[2] = (macaddr1_high >> 8) & 0xff;
>> >> +			macaddr[3] = macaddr1_high & 0xff;
>> >> +			macaddr[4] = (macaddr0_low >> 24) & 0xff;
>> >> +			macaddr[5] = (macaddr0_low >> 16) & 0xff;
>> >> +		} else {
>> >> +			macaddr[0] = (macaddr0_low >> 8) & 0xff;
>> >> +			macaddr[1] = macaddr0_low & 0xff;
>> >> +			macaddr[2] = (macaddr0_high >> 24) & 0xff;
>> >> +			macaddr[3] = (macaddr0_high >> 16) & 0xff;
>> >> +			macaddr[4] = (macaddr0_high >> 8) & 0xff;
>> >> +			macaddr[5] = macaddr0_high & 0xff;
>> >> +		}
>> >
>> >It makes no sense to have a IMX_MAX_ENET_NUM define when the code
>> >assumes that the only valid value is 2.
>> >
>> You mean remove the "IMX_MAX_ENET_NUM" ?
>>
>> >All this is probably far more readable and less fishy when you move
>> >the fixup of a single enet device to a extra function which you call
>> >from the loop.
>> >
>> Because imx6sx has two enet MACs, and the function is called for
>imx6qdl/imx6sl/imx6sx, so add the loop in here.
>> For imx6qdl/imx6sl, there just have one MAC, the second loop don't go
>through the flow.
>> Do you have other suggestion ?
>
>What I want to say is: When you have a loop and the loop body gets to
>complicated, then it often improves readability to move the loop body to
>an extra function, like this:
>
>static int imx6_enet_mac_init_one(struct device_node *enet, const u8 *mac)
>{
>	struct property *newmac;
>	u8 mac[6];
>
>	if (of_get_mac_address(enet))
>		return 0;
>
>	newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
>	if (!newmac)
>		return -ENOMEM;
>
>	newmac->length = 6;
>	newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
>	newmac->value = kmemdup(mac, 6, GFP_KERNEL);
>
>	of_update_property(enet_np, newmac);
>
>	release_stuff();
>}
>
>int imx6_enet_mac_init(const char *compatible) {
>	struct device_node *from = NULL;
>	u8 mac[6];
>
>	macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
>	macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
>	macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));
>
>	mac[0] = ...;
>
>	enet_np = of_find_compatible_node(NULL, NULL, compatible);
>	if (!enet_np)
>		return 0;
>
>	imx6_enet_mac_init_one(enet_np, mac);
>
>	enet_np = of_find_compatible_node(enet_np, NULL, compatible);
>	if (!enet_np)
>		return 0;
>
>	mac[0] = ...;
>
>	imx6_enet_mac_init_one(enet_no, mac);
>}
>
>(here I removed the loop which makes the code even more straight
>forward)
>
>Sascha
>
Sascha, thanks for your suggestion !  It is more readable. I will send out the patch V2.
Shawn Guo May 21, 2014, 6:46 a.m. UTC | #5
On Tue, May 20, 2014 at 05:24:01PM +0800, Duan Fugang-B38611 wrote:
> >> +#define OCOTP_MACn(n)		(0x00000620 + (n) * 0x10)
> >> +#define IMX_MAX_ENET_NUM	2
> >> +void __init imx6_enet_mac_init(const char *compatible)
> >
> >static
> >
> The .fun() will be called for imx6sl, imx6sx(the latest chip) machine files.

Then, it shouldn't be put in mach-imx6q.c which will be built only when
CONFIG_SOC_IMX6Q is enabled.

Shawn
Shawn Guo May 22, 2014, 6:12 a.m. UTC | #6
On Tue, May 20, 2014 at 02:11:06PM +0800, Fugang Duan wrote:
> Enet get MAC address order:
> From module parameters or kernel command line -> device tree ->
> pfuse -> mac registers set by bootloader -> random mac address.
> 
> When there have no "fec.macaddr" parameters set in kernel command
> line, enet driver get MAC address from device tree. And then if
> the MAC address set in device tree and is valid, enet driver get
> MAC address from device tree. Otherwise, enet get MAC address from
> pfuse. So, in the condition, update the MAC address (read from pfuse)
> to device tree.
> 
> Signed-off-by: Fugang Duan <B38611@freescale.com>

I would think this is a board level configuration than SoC one.  Though
the register name in Reference Manual, OCOTP_MAC0 and OCOTP_MAC1,
recommends that these fuse bits can be used to store MAC address, it's
really up to board designers how to use these fuse bits, e.g. how the
MAC bytes will be stored in these 64 fuse bits, or on some board designs
which do not have Ethernet interface at all, these bits can totally be
used for other purpose.

So to me, it's inappropriate to assume that these fuse bits always hold
MAC address, and do this setup in kernel unconditionally for every
board.  I think it's more reasonable to do this setup in bootloader,
which should be more board specific and can understand these fuse bits
better.

Shawn
Fugang Duan May 22, 2014, 7:34 a.m. UTC | #7
From: Shawn Guo <shawn.guo@freescale.com>
Data: Thursday, May 22, 2014 2:13 PM

>To: Duan Fugang-B38611
>Cc: Li Frank-B20596; linux-arm-kernel@lists.infradead.org;
>kernel@pengutronix.de
>Subject: Re: [PATCH] ARM: imx6: init enet MAC address
>
>On Tue, May 20, 2014 at 02:11:06PM +0800, Fugang Duan wrote:
>> Enet get MAC address order:
>> From module parameters or kernel command line -> device tree -> pfuse
>> -> mac registers set by bootloader -> random mac address.
>>
>> When there have no "fec.macaddr" parameters set in kernel command
>> line, enet driver get MAC address from device tree. And then if the
>> MAC address set in device tree and is valid, enet driver get MAC
>> address from device tree. Otherwise, enet get MAC address from pfuse.
>> So, in the condition, update the MAC address (read from pfuse) to
>> device tree.
>>
>> Signed-off-by: Fugang Duan <B38611@freescale.com>
>
>I would think this is a board level configuration than SoC one.  Though
>the register name in Reference Manual, OCOTP_MAC0 and OCOTP_MAC1,
>recommends that these fuse bits can be used to store MAC address, it's
>really up to board designers how to use these fuse bits, e.g. how the MAC
>bytes will be stored in these 64 fuse bits, or on some board designs which
>do not have Ethernet interface at all, these bits can totally be used for
>other purpose.
>
>So to me, it's inappropriate to assume that these fuse bits always hold
>MAC address, and do this setup in kernel unconditionally for every board.
>I think it's more reasonable to do this setup in bootloader, which should
>be more board specific and can understand these fuse bits better.
>
>Shawn

Shawn,  if so, we don't need to upstream the patch in kernel.
Thanks for your information.

Andy
diff mbox

Patch

diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 4facd01..5c69325 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -145,6 +145,7 @@  void imx6sl_set_wait_clk(bool enter);
 
 void imx_cpu_die(unsigned int cpu);
 int imx_cpu_kill(unsigned int cpu);
+void imx6_enet_mac_init(const char *compatible);
 
 #ifdef CONFIG_SUSPEND
 void v7_cpu_resume(void);
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index e60456d..2bec13d 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -22,6 +22,7 @@ 
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/of_net.h>
 #include <linux/of_platform.h>
 #include <linux/pm_opp.h>
 #include <linux/pci.h>
@@ -164,6 +165,85 @@  static int ar8035_phy_fixup(struct phy_device *dev)
 	return 0;
 }
 
+#define OCOTP_MACn(n)		(0x00000620 + (n) * 0x10)
+#define IMX_MAX_ENET_NUM	2
+void __init imx6_enet_mac_init(const char *compatible)
+{
+	struct device_node *ocotp_np, *enet_np, *from = NULL;
+	void __iomem *base;
+	struct property *newmac;
+	u32 macaddr0_low;
+	u32 macaddr0_high = 0;
+	u32 macaddr1_high = 0;
+	u8 *macaddr;
+	int i;
+
+	for (i = 0; i < IMX_MAX_ENET_NUM; i++) {
+		enet_np = of_find_compatible_node(from, NULL, compatible);
+		if (!enet_np)
+			return;
+
+		from = enet_np;
+
+		if (of_get_mac_address(enet_np))
+			goto put_enet_node;
+
+		ocotp_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
+		if (!ocotp_np) {
+			pr_warn("failed to find ocotp node\n");
+			goto put_enet_node;
+		}
+
+		base = of_iomap(ocotp_np, 0);
+		if (!base) {
+			pr_warn("failed to map ocotp\n");
+			goto put_ocotp_node;
+		}
+
+		macaddr0_low = readl_relaxed(base + OCOTP_MACn(1));
+		if (i)
+			macaddr1_high = readl_relaxed(base + OCOTP_MACn(2));
+		else
+			macaddr0_high = readl_relaxed(base + OCOTP_MACn(0));
+
+		newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
+		if (!newmac)
+			goto put_ocotp_node;
+
+		newmac->value = newmac + 1;
+		newmac->length = 6;
+		newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
+		if (!newmac->name) {
+			kfree(newmac);
+			goto put_ocotp_node;
+		}
+
+		macaddr = newmac->value;
+		if (i) {
+			macaddr[0] = (macaddr1_high >> 24) & 0xff;
+			macaddr[1] = (macaddr1_high >> 16) & 0xff;
+			macaddr[2] = (macaddr1_high >> 8) & 0xff;
+			macaddr[3] = macaddr1_high & 0xff;
+			macaddr[4] = (macaddr0_low >> 24) & 0xff;
+			macaddr[5] = (macaddr0_low >> 16) & 0xff;
+		} else {
+			macaddr[0] = (macaddr0_low >> 8) & 0xff;
+			macaddr[1] = macaddr0_low & 0xff;
+			macaddr[2] = (macaddr0_high >> 24) & 0xff;
+			macaddr[3] = (macaddr0_high >> 16) & 0xff;
+			macaddr[4] = (macaddr0_high >> 8) & 0xff;
+			macaddr[5] = macaddr0_high & 0xff;
+		}
+
+		of_update_property(enet_np, newmac);
+
+put_ocotp_node:
+		of_node_put(ocotp_np);
+put_enet_node:
+		of_node_put(enet_np);
+	}
+}
+
 #define PHY_ID_AR8035 0x004dd072
 
 static void __init imx6q_enet_phy_init(void)
@@ -228,6 +308,13 @@  put_node:
 	of_node_put(np);
 }
 
+static inline void imx6q_enet_init(void)
+{
+	imx6_enet_mac_init("fsl,imx6q-fec");
+	imx6q_enet_phy_init();
+	imx6q_1588_init();
+}
+
 static void __init imx6q_axi_init(void)
 {
 	struct regmap *gpr;
@@ -274,13 +361,12 @@  static void __init imx6q_init_machine(void)
 	if (parent == NULL)
 		pr_warn("failed to initialize soc device\n");
 
-	imx6q_enet_phy_init();
 
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
 
+	imx6q_enet_init();
 	imx_anatop_init();
 	cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();
-	imx6q_1588_init();
 	imx6q_axi_init();
 }
 
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c
index ad32338..cb001d4 100644
--- a/arch/arm/mach-imx/mach-imx6sl.c
+++ b/arch/arm/mach-imx/mach-imx6sl.c
@@ -19,7 +19,7 @@ 
 #include "common.h"
 #include "cpuidle.h"
 
-static void __init imx6sl_fec_init(void)
+static void __init imx6sl_fec_clk_init(void)
 {
 	struct regmap *gpr;
 
@@ -35,6 +35,12 @@  static void __init imx6sl_fec_init(void)
 	}
 }
 
+static inline void imx6sl_fec_init(void)
+{
+	imx6sl_fec_clk_init();
+	imx6_enet_mac_init("fsl,imx6sl-fec");
+}
+
 static void __init imx6sl_init_late(void)
 {
 	/* imx6sl reuses imx6q cpufreq driver */