Skip to contentSkip to conversation

i40e: Look up MAC address in Open Firmware or IDPROM

PATCH Superseded Sowmini Varadhan 5 participants 13 messages Nov 4, 2015 – Dec 3, 2015

Subsystems (4)

v6 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

PATCH v6 1/1 i40e: Look up MAC address in Open Firmware or IDPROM

This is the i40e equivalent of commit c762dff24c06 ("ixgbe: Look up MAC address in Open Firmware or IDPROM").

As with that fix, attempt to look up the MAC address in Open Firmware on systems that support it, and use IDPROM on SPARC if no OF address is found.

In the case of the i40e there is an assumption that the default mac address has already been set up as the primary mac filter on probe, so if this filter is obtained from the Open Firmware or IDPROM, an explicit write is needed via i40e_aq_mac_address_write() and i40e_aq_add_macvlan() invocation.

---
v2, v3: Andy Shevchenko comments
v4: Shannon Nelson review: explicitly set up mac filters before register_netdev
v5: Shannon Nelson code style comments
v6: Shannon Nelson code style comments

 drivers/net/ethernet/intel/i40e/i40e_main.c |   83 ++++++++++++++++++++++++++-
 1 files changed, 82 insertions(+), 1 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +82 -1
index b825f97..e355873 100644
@@ -24,6 +24,15 @@
  *
  ******************************************************************************/
 
+#include <linux/etherdevice.h>
+#include <linux/of_net.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_SPARC
+#include <asm/idprom.h>
+#include <asm/prom.h>
+#endif
+
 /* Local includes */
 #include "i40e.h"
 #include "i40e_diag.h"
@@ -9213,6 +9222,44 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
 }
 
 /**
+ * i40e_macaddr_init - explicitly write the mac address filters.
+ *
+ * @vsi: pointer to the vsi.
+ * @macaddr: the MAC address
+ *
+ * This is needed when the macaddr has been obtained by other
+ * means than the default, e.g., from Open Firmware or IDPROM.
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_macaddr_init(struct i40e_vsi *vsi, u8 *macaddr)
+{
+	int ret, aq_err;
+	struct i40e_aqc_add_macvlan_element_data element;
+
+	ret = i40e_aq_mac_address_write(&vsi->back->hw,
+					I40E_AQC_WRITE_TYPE_LAA_WOL,
+					macaddr, NULL);
+	if (ret) {
+		dev_info(&vsi->back->pdev->dev,
+			 "Addr change for VSI failed: %d\n", ret);
+		return -EADDRNOTAVAIL;
+	}
+
+	memset(&element, 0, sizeof(element));
+	ether_addr_copy(element.mac_addr, macaddr);
+	element.flags = cpu_to_le16(I40E_AQC_MACVLAN_ADD_PERFECT_MATCH);
+	ret = i40e_aq_add_macvlan(&vsi->back->hw, vsi->seid, &element, 1, NULL);
+	aq_err = vsi->back->hw.aq.asq_last_status;
+	if (aq_err != I40E_AQ_RC_OK) {
+		dev_info(&vsi->back->pdev->dev,
+			 "add filter failed err %s aq_err %s\n",
+			 i40e_stat_str(&vsi->back->hw, ret),
+			 i40e_aq_str(&vsi->back->hw, aq_err));
+	}
+	return ret;
+}
+
+/**
  * i40e_vsi_setup - Set up a VSI by a given type
  * @pf: board private structure
  * @type: VSI type
@@ -9341,6 +9388,9 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
 		ret = i40e_config_netdev(vsi);
 		if (ret)
 			goto err_netdev;
+		ret = i40e_macaddr_init(vsi, pf->hw.mac.addr);
+		if (ret)
+			goto err_netdev;
 		ret = register_netdev(vsi->netdev);
 		if (ret)
 			goto err_netdev;
@@ -10163,6 +10213,35 @@ static void i40e_print_features(struct i40e_pf *pf)
 }
 
 /**
+ * i40e_get_platform_mac_addr - get platform-specific MAC address
+ *
+ * @pdev: PCI device information struct
+ * @mac_addr: the MAC address to be returned
+ *
+ * Look up the MAC address in Open Firmware  on systems that support it,
+ * and use IDPROM on SPARC if no OF address is found.
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_platform_mac_addr(struct pci_dev *pdev, u8 *mac_addr)
+{
+	struct device_node *dp = pci_device_to_OF_node(pdev);
+	const unsigned char *addr;
+
+	addr = of_get_mac_address(dp);
+	if (addr) {
+		ether_addr_copy(mac_addr, addr);
+		return 0;
+	}
+#ifdef CONFIG_SPARC
+	ether_addr_copy(mac_addr, idprom->id_ethaddr);
+	return 0;
+#else
+	return -EINVAL;
+#endif /* CONFIG_SPARC */
+}
+
+/**
  * i40e_probe - Device initialization routine
  * @pdev: PCI device information struct
  * @ent: entry in i40e_pci_tbl
@@ -10360,7 +10439,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		i40e_aq_stop_lldp(hw, true, NULL);
 	}
 
-	i40e_get_mac_addr(hw, hw->mac.addr);
+	err = i40e_get_platform_mac_addr(pdev, hw->mac.addr);
+	if (err)
+		i40e_get_mac_addr(hw, hw->mac.addr);
 	if (!is_valid_ether_addr(hw->mac.addr)) {
 		dev_info(&pdev->dev, "invalid MAC address %pM\n", hw->mac.addr);
 		err = -EIO;
Signature · 1 line
1.7.1
Acked-by on v6 1/1
#1 lore raw
Quoted 25 lines

From: Sowmini Varadhan [mailto:sowmini.varadhan at oracle.com]
Sent: Wednesday, November 04, 2015 3:21 PM

This is the i40e equivalent of commit c762dff24c06 ("ixgbe: Look up MAC address in Open Firmware or IDPROM").

As with that fix, attempt to look up the MAC address in Open Firmware on systems that support it, and use IDPROM on SPARC if no OF address is found.

In the case of the i40e there is an assumption that the default mac address has already been set up as the primary mac filter on probe, so if this filter is obtained from the Open Firmware or IDPROM, an explicit write is needed via i40e_aq_mac_address_write() and i40e_aq_add_macvlan() invocation.

---
v2, v3: Andy Shevchenko comments
v4: Shannon Nelson review: explicitly set up mac filters before register_netdev
v5: Shannon Nelson code style comments
v6: Shannon Nelson code style comments

Quoted 4 lines
 drivers/net/ethernet/intel/i40e/i40e_main.c |   83
++++++++++++++++++++++++++-
 1 files changed, 82 insertions(+), 1 deletions(-)
maintainer
#2 lore raw
In reply to Sowmini Varadhan

From: Sowmini Varadhan <[email protected]>
Date: Wed, 4 Nov 2015 18:21:00 -0500

Quoted 7 lines

This is the i40e equivalent of commit c762dff24c06 ("ixgbe: Look up MAC address in Open Firmware or IDPROM").

As with that fix, attempt to look up the MAC address in Open Firmware on systems that support it, and use IDPROM on SPARC if no OF address is found.

Quoted 8 lines

In the case of the i40e there is an assumption that the default mac address has already been set up as the primary mac filter on probe, so if this filter is obtained from the Open Firmware or IDPROM, an explicit write is needed via i40e_aq_mac_address_write() and i40e_aq_add_macvlan() invocation.

Thanks for doing this.

Longer term we really need an abstract interface by which architectures can provide a "system" or "firmware" MAC address which applies to a given 'dev'.

Because these SPARC ifdef'y things really should propagate to driver after driver after driver.

I'll see if I can cook something up.

maintainer
#3 lore raw

From: David Miller <[email protected]>
Date: Thu, 05 Nov 2015 10:31:26 -0500 (EST)

Quoted 1 line

I'll see if I can cook something up.

How does this look?

====================
net: Add eth_platform_get_mac_address() helper.

A repeating pattern in drivers has become to use OF node information and, if not found, platform specific host information to extract the ethernet address for a given device.

Currently this is done with a call to of_get_mac_mac_address() and then some ifdef'd stuff for SPARC.

Consolidate this into a portable routine, and provide the arch_get_platform_mac_address() weak function hook for all architectures to implement if they want.

arch/sparc/kernel/idprom.c +7 -0
index 6bd7501..f95dd11 100644
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/export.h>
+#include <linux/etherdevice.h>
 
 #include <asm/oplib.h>
 #include <asm/idprom.h>
@@ -60,6 +61,12 @@ static void __init display_system_type(unsigned char machtype)
 {
 }
 #endif
+
+unsigned char *arch_get_platform_mac_address(void)
+{
+	return idprom->id_ethaddr;
+}
+
 /* Calculate the IDPROM checksum (xor of the data bytes). */
 static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
 {
include/linux/etherdevice.h +3 -0
index eb049c6..37ff4a6 100644
@@ -29,6 +29,9 @@
 #include <asm/bitsperlong.h>
 
 #ifdef __KERNEL__
+struct device;
+int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr);
+unsigned char *arch_get_platform_get_mac_address(void);
 u32 eth_get_headlen(void *data, unsigned int max_len);
 __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
 extern const struct header_ops eth_header_ops;
net/ethernet/eth.c +32 -0
index 9e63f25..1cb9204f 100644
@@ -52,6 +52,8 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/if_ether.h>
+#include <linux/of_net.h>
+#include <linux/pci.h>
 #include <net/dst.h>
 #include <net/arp.h>
 #include <net/sock.h>
@@ -485,3 +487,33 @@ static int __init eth_offload_init(void)
 }
 
 fs_initcall(eth_offload_init);
+
+unsigned char * __weak arch_get_platform_mac_address(void)
+{
+	return NULL;
+}
+
+int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr)
+{
+	const unsigned char *addr;
+	struct device_node *dp;
+
+	if (dev_is_pci(dev))
+		dp = pci_device_to_OF_node(to_pci_dev(dev));
+	else
+		dp = dev->of_node;
+
+	addr = NULL;
+	if (dp)
+		addr = of_get_mac_address(dp);
+	if (!addr)
+		addr = arch_get_platform_mac_address();
+
+	if (addr) {
+		ether_addr_copy(mac_addr, addr);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL(eth_platform_get_mac_address);
#4 lore raw
Quoted 6 lines · David Miller

From: David Miller <[email protected]>
Date: Thu, 05 Nov 2015 10:31:26 -0500 (EST)

Quoted 1 line

I'll see if I can cook something up.

How does this look?

Looks good to me,

Do you want me to respin patch v7 with this? Or update ixgbe/i40e to use this later, after this goes in?

--Sowmini

maintainer
#5 lore raw

From: Sowmini Varadhan <[email protected]>
Date: Thu, 5 Nov 2015 11:28:31 -0500

Quoted 12 lines · David Miller
Quoted 6 lines

From: David Miller <[email protected]>
Date: Thu, 05 Nov 2015 10:31:26 -0500 (EST)

Quoted 1 line

I'll see if I can cook something up.

How does this look?

Looks good to me,

Do you want me to respin patch v7 with this? Or update ixgbe/i40e to use this later, after this goes in?

The intention is to let your patch go in as-is, then try and update ixgbe/i40e later in net-next or similar.

#6 lore raw
Quoted 3 lines · David Miller

The intention is to let your patch go in as-is, then try and update ixgbe/i40e later in net-next or similar.

Sounds good, I can take care of ixgbe/i40e after that happens.

#7 lore raw
In reply to David Miller
Quoted 14 lines

From: David Miller [mailto:davem at davemloft.net]
Sent: Thursday, November 05, 2015 8:29 AM

From: Sowmini Varadhan <[email protected]>
Date: Thu, 5 Nov 2015 11:28:31 -0500

Quoted 8 lines · David Miller
Quoted 6 lines

From: David Miller <[email protected]>
Date: Thu, 05 Nov 2015 10:31:26 -0500 (EST)

Quoted 1 line

I'll see if I can cook something up.

How does this look?

Quoted 8 lines
Quoted 3 lines

Looks good to me,

Do you want me to respin patch v7 with this? Or update ixgbe/i40e to

use

Quoted 1 line

this later, after this goes in?

The intention is to let your patch go in as-is, then try and update ixgbe/i40e later in net-next or similar.

That works for us as well - thanks!
sln

#8 lore raw
In reply to David Miller
Quoted 6 lines · David Miller

From: David Miller <[email protected]>
Date: Thu, 05 Nov 2015 10:31:26 -0500 (EST)

Quoted 1 line

I'll see if I can cook something up.

How does this look?

I like it, though couple of style related comments.

Quoted 80 lines

====================
net: Add eth_platform_get_mac_address() helper.

A repeating pattern in drivers has become to use OF node information and, if not found, platform specific host information to extract the ethernet address for a given device.

Currently this is done with a call to of_get_mac_mac_address() and then some ifdef'd stuff for SPARC.

Consolidate this into a portable routine, and provide the arch_get_platform_mac_address() weak function hook for all architectures to implement if they want.

arch/sparc/kernel/idprom.c +7 -0
index 6bd7501..f95dd11 100644
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/export.h>
+#include <linux/etherdevice.h>
 
 #include <asm/oplib.h>
 #include <asm/idprom.h>
@@ -60,6 +61,12 @@ static void __init display_system_type(unsigned char machtype)
 {
 }
 #endif
+
+unsigned char *arch_get_platform_mac_address(void)
+{
+       return idprom->id_ethaddr;
+}
+
 /* Calculate the IDPROM checksum (xor of the data bytes). */
 static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
 {
include/linux/etherdevice.h +3 -0
index eb049c6..37ff4a6 100644
@@ -29,6 +29,9 @@
 #include <asm/bitsperlong.h>
 
 #ifdef __KERNEL__
+struct device;
+int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr);
+unsigned char *arch_get_platform_get_mac_address(void);
 u32 eth_get_headlen(void *data, unsigned int max_len);
 __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
 extern const struct header_ops eth_header_ops;
net/ethernet/eth.c +9 -0
index 9e63f25..1cb9204f 100644
@@ -52,6 +52,8 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/if_ether.h>
+#include <linux/of_net.h>
+#include <linux/pci.h>
 #include <net/dst.h>
 #include <net/arp.h>
 #include <net/sock.h>
@@ -485,3 +487,33 @@ static int __init eth_offload_init(void)
 }
 
 fs_initcall(eth_offload_init);
+
+unsigned char * __weak arch_get_platform_mac_address(void)
+{
+       return NULL;
+}
+
+int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr)

net/ethernet/eth.c static int __init eth_offload_init(void) · line 506

Quoted 10 lines
net/ethernet/eth.c +10 -0
+{
+       const unsigned char *addr;
+       struct device_node *dp;
+
+       if (dev_is_pci(dev))
+               dp = pci_device_to_OF_node(to_pci_dev(dev));
+       else
+               dp = dev->of_node;
+
+       addr = NULL;

Maybe we can use definition block for this assignment?

net/ethernet/eth.c static int __init eth_offload_init(void) · line 512

Quoted 6 lines
net/ethernet/eth.c +6 -0
+       if (dp)
+               addr = of_get_mac_address(dp);
+       if (!addr)
+               addr = arch_get_platform_mac_address();
+
+       if (addr) {

What about

if (!addr)
return -ENODATA;

(Yes, ENODATA looks suitable for me)

Quoted 7 lines
net/ethernet/eth.c +7 -0
+               ether_addr_copy(mac_addr, addr);
+               return 0;
+       }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(eth_platform_get_mac_address);
Signature · 2 lines
With Best Regards,
Andy Shevchenko
maintainer
#9 lore raw

From: Andy Shevchenko <[email protected]>
Date: Thu, 5 Nov 2015 20:13:21 +0200

Quoted 4 lines

What about

if (!addr)
return -ENODATA;

I totally disagree. of_get_phy_mode() and other similar attribute probing mechanisms use -ENODEV.

#10 lore raw
Quoted 10 lines · David Miller

From: Andy Shevchenko <[email protected]>
Date: Thu, 5 Nov 2015 20:13:21 +0200

Quoted 4 lines

What about

if (!addr)
return -ENODATA;

I totally disagree. of_get_phy_mode() and other similar attribute probing mechanisms use -ENODEV.

Okay, then just
if (!addr)
return -ENODEV;

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#11 lore raw

I get an error -11 on driver init with this patch applied, I can revert it and everything works normally. Dmesg screenshot is attached, can supply complete dmesg log if needed. --Andrew

Quoted 28 lines

-----Original Message-----
From: Intel-wired-lan [mailto:intel-wired-lan-bounces at lists.osuosl.org] On Behalf Of Andy Shevchenko
Sent: Thursday, November 05, 2015 11:33 AM
To: David Miller <[email protected]>
Cc: Sowmini Varadhan <[email protected]>; linux-
kernel at vger.kernel.org; intel-wired-lan at lists.osuosl.org; netdev <[email protected]>
Subject: Re: [Intel-wired-lan] [PATCH v6] i40e: Look up MAC address in Open Firmware or IDPROM

Quoted 10 lines · David Miller

From: Andy Shevchenko <[email protected]>
Date: Thu, 5 Nov 2015 20:13:21 +0200

Quoted 4 lines

What about

if (!addr)
return -ENODATA;

I totally disagree. of_get_phy_mode() and other similar attribute probing mechanisms use -ENODEV.

Okay, then just
if (!addr)
return -ENODEV;

Quoted 7 lines

--
With Best Regards,
Andy Shevchenko
_______________________________________________
Intel-wired-lan mailing list
Intel-wired-lan at lists.osuosl.org
http://lists.osuosl.org/mailman/listinfo/intel-wired-lan

-------------- next part --------------
A non-text attachment was scrubbed...
Name: dmesgerror.jpg
Type: image/jpeg
Size: 170030 bytes
Desc: dmesgerror.jpg
URL: <http://lists.osuosl.org/pipermail/intel-wired-lan/attachments/20151203/f96452e4/attachment-0001.jpg>

#12 lore raw
Quoted 4 lines · AndrewX

I get an error -11 on driver init with this patch applied, I can revert it and everything works normally. Dmesg screenshot is attached, can supply complete dmesg log if needed.

Yes, that's the same thing that I'm running into as well. Using this patch makes this work. But this adds some ugly ifdef's, and other methods should be explored.

drivers/net/ethernet/intel/i40e/i40e_main.c +2 -0
@@ -9102,9 +9102,11 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 ty
                ret = i40e_config_netdev(vsi);
                if (ret)
                        goto err_netdev;
+#if defined(CONFIG_SPARC) || defined(CONFIG_OF)
                ret = i40e_macaddr_init(vsi, pf->hw.mac.addr);
                if (ret)
                        goto err_netdev;
+#endif
                ret = register_netdev(vsi->netdev);
                if (ret)
                        goto err_netdev;