net: wireless: bcmdhd: Use DTB to get MAC address
Michael Hsu [Tue, 29 Dec 2015 00:53:37 +0000 (16:53 -0800)]
Use the DTB function of_get_mac_address() to get wifi MAC address.

Bug 1711453

Change-Id: I14a31ce0fd3ab2b6db18a4c9f569b8fb0197101b
Signed-off-by: Michael Hsu <mhsu@nvidia.com>
Reviewed-on: http://git-master/r/927233
GVS: Gerrit_Virtual_Submit
Reviewed-by: Nagaraj Annaiah <nannaiah@nvidia.com>
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>

Documentation/devicetree/bindings/net/wireless/bcmdhd/bcmdhd-wlan.txt
arch/arm/boot/dts/tegra124-platforms/tegra124-comms.dtsi
arch/arm/boot/dts/tegra124-platforms/tegra124-green-arrow-comms.dtsi
arch/arm/boot/dts/tegra124-platforms/tegra124-tn8-comms.dtsi
arch/arm64/boot/dts/tegra210-platforms/tegra210-comms-p2530-0930.dtsi
arch/arm64/boot/dts/tegra210-platforms/tegra210-comms.dtsi
arch/arm64/boot/dts/tegra210-platforms/tegra210-hawkeye-comms.dtsi
arch/arm64/boot/dts/tegra210-platforms/tegra210-loki-e-comms.dtsi
drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
drivers/of/of_net.c

index f42b43c..641b983 100644 (file)
@@ -11,6 +11,19 @@ Optional properties:
 - "interrupts" is a wake on wireless gpio interrupt pin
 - "edp-consumer-name" is required to populate wifi edp consumer name
 
+MAC address properties (using the of_get_mac_address() function,
+checked in this order):
+- 'mac-address' is the "most recent" MAC address (6 octet binary property)
+- 'local-mac-address' is the default MAC address (6 octet binary property)
+- 'address' is supposed to contain a virtual address of the register set, but
+  some DTS files have redefined this property to be the MAC address
+  (6 octet binary property)
+- 'mac-address-chosen-dtb-node' is the property name of a string property under
+  the /chosen dtb node which contains the MAC address string
+  "xx:xx:xx:xx:xx:xx"
+- 'mac-address-file' is a string property which contains the path of a file
+  which contains the MAC address string "xx:xx:xx:xx:xx:xx"
+
 Example:
 bcmdhd_wlan {
        compatible = "android,tegra-bcmdhd-wlan";
@@ -19,6 +32,21 @@ bcmdhd_wlan {
        wlan-pwr-gpio = <&gpio TEGRA_GPIO(X, 7) 0>;
        wlan-rst-gpio = <&gpio TEGRA_GPIO(CC, 5) 0>;
        edp-consumer-name = "primary-wifi";
+       /* possible methods of specifying MAC address
+        * (in first to last order)
+        */
+       mac-address = [00 04 4b fe ed be];
+       local-mac-address = [00 04 4b fe ed bf];
+       /* the next method requires the /chosen dtb node to have a string
+        * property named "nvidia,wifi-mac" which contains the MAC address
+        * string "xx:xx:xx:xx:xx:xx"
+        */
+       mac-address-chosen-dtb-node = "nvidia,wifi-mac";
+       /* the next method requires the filesystem file
+        * /mnt/factory/wifi/wifi_mac.txt to contain the MAC address string
+        * "xx:xx:xx:xx:xx:xx"
+        */
+       mac-address-file = "/mnt/factory/wifi/wifi_mac.txt";
 };
 ===============================================================================
 * bcmdhd2-wlan devicetree bindings
@@ -34,6 +62,11 @@ Optional properties:
 - "interrupts" is a wake on wireless gpio interrupt pin
 - "edp-consumer-name" is required to populate wifi edp consumer name
 
+MAC address properties (using the of_get_mac_address() function):
+- the bcmdhd2 2nd driver instance is no longer used, so new features
+  (such as using the of_get_mac_address() function to get the MAC address)
+  have not been ported to bcmdhd2 driver
+
 Example:
 bcm4329_wlan2_ {
        compatible = "nvidia,tegra-bcmdhd2-wlan";
index 3da0e3e..6c2afb0 100644 (file)
@@ -51,5 +51,8 @@
                wlan-pwr-gpio = <&gpio TEGRA_GPIO(X, 7) 0>;
                wlan-rst-gpio = <&gpio TEGRA_GPIO(CC, 5) 0>;
                status = "okay";
+               /* wifi MAC address */
+               mac-address-chosen-dtb-node = "nvidia,wifi-mac";
+               mac-address-file = "/mnt/factory/wifi/wifi_mac.txt";
        };
 };
index ee3f2ac..3a8ea06 100644 (file)
@@ -20,6 +20,9 @@
 
 / {
        bcmdhd_wlan {
+               /* wifi MAC address */
+               mac-address-chosen-dtb-node = "nvidia,wifi-mac";
+               mac-address-file = "/mnt/factory/wifi/wifi_mac.txt";
                country_code_map {
                        CC1 {
                                iso_abbrev = "XV";
index 844d0c3..2720c9a 100644 (file)
@@ -20,6 +20,9 @@
 
 / {
        bcmdhd_wlan {
+               /* wifi MAC address */
+               mac-address-chosen-dtb-node = "nvidia,wifi-mac";
+               mac-address-file = "/mnt/factory/wifi/wifi_mac.txt";
                country_code_map {
                        CC1 {
                                iso_abbrev = "Q2";
index 3af6934..0f51ee5 100644 (file)
@@ -32,5 +32,8 @@
                interrupts = <TEGRA_GPIO(H, 2) 0x14>;
                wlan-pwr-gpio = <&gpio TEGRA_GPIO(H, 0) 0>;
                status = "okay";
+               /* wifi MAC address */
+               mac-address-chosen-dtb-node = "nvidia,wifi-mac";
+               mac-address-file = "/mnt/factory/wifi/wifi_mac.txt";
        };
 };
index 3045d88..c41cfa3 100644 (file)
@@ -32,5 +32,8 @@
                wlan-pwr-gpio = <&gpio TEGRA_GPIO(H, 0) 0>;
                wlan-rst-gpio = <&gpio TEGRA_GPIO(H, 1) 0>;
                status = "okay";
+               /* wifi MAC address */
+               mac-address-chosen-dtb-node = "nvidia,wifi-mac";
+               mac-address-file = "/mnt/factory/wifi/wifi_mac.txt";
        };
 };
index c47a074..966c809 100644 (file)
@@ -13,6 +13,9 @@
        };
 
        bcmdhd_wlan {
+               /* wifi MAC address */
+               mac-address-chosen-dtb-node = "nvidia,wifi-mac";
+               mac-address-file = "/mnt/factory/wifi/wifi_mac.txt";
                country_code_map {
                        CC1 {
                                iso_abbrev = "XV";
index 6de8849..e383138 100644 (file)
@@ -30,6 +30,9 @@
                interrupts = <TEGRA_GPIO(H, 2) 0x14>;
                wlan-pwr-gpio = <&gpio TEGRA_GPIO(H, 0) 0>;
                status = "okay";
+               /* wifi MAC address */
+               mac-address-chosen-dtb-node = "nvidia,wifi-mac";
+               mac-address-file = "/mnt/factory/wifi/wifi_mac.txt";
        };
 
        bcm4329_wlan2_ {
index fb01ad2..c3d54cc 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/wlan_plat.h>
 #endif
 #include <linux/of_gpio.h>
+#include <linux/of_net.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/irq.h>
@@ -216,120 +217,21 @@ int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_presen
 
 }
 
-#define ARDBEG_WIFI_MAC_ADDR_FILE      "/mnt/factory/wifi/wifi_mac.txt"
-static int _wifi_get_mac_addr_file(unsigned char *buf)
-{
-       struct file *fp;
-       int rdlen;
-       char str[32];
-       int mac[6];
-       int ret = 0;
-
-       /* open wifi mac address file */
-       fp = filp_open(ARDBEG_WIFI_MAC_ADDR_FILE, O_RDONLY, 0);
-       if (IS_ERR(fp)) {
-               DHD_ERROR(("%s: cannot open %s\n",
-                       __FUNCTION__, ARDBEG_WIFI_MAC_ADDR_FILE));
-               return -ENOENT;
-       }
-
-       /* read wifi mac address file */
-       memset(str, 0, sizeof(str));
-       rdlen = kernel_read(fp, fp->f_pos, str, 17);
-       if (rdlen > 0)
-               fp->f_pos += rdlen;
-       if (rdlen != 17) {
-               DHD_ERROR(("%s: bad mac address file"
-                       " - len %d < 17",
-                       __FUNCTION__, rdlen));
-               ret = -ENOENT;
-       } else if (sscanf(str, "%x:%x:%x:%x:%x:%x",
-               &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
-               DHD_ERROR(("%s: bad mac address file"
-                       " - must contain xx:xx:xx:xx:xx:xx\n",
-                       __FUNCTION__));
-               ret = -ENOENT;
-       } else {
-               DHD_ERROR(("%s: using wifi mac %02x:%02x:%02x:%02x:%02x:%02x\n",
-                       __FUNCTION__,
-                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
-               buf[0] = (unsigned char) mac[0];
-               buf[1] = (unsigned char) mac[1];
-               buf[2] = (unsigned char) mac[2];
-               buf[3] = (unsigned char) mac[3];
-               buf[4] = (unsigned char) mac[4];
-               buf[5] = (unsigned char) mac[5];
-       }
-
-       /* close wifi mac address file */
-       filp_close(fp, NULL);
-
-       return ret;
-}
-
-/* Get MAC address from the specified DTB path */
-static int _wifi_get_mac_address_dtb(const char *node_name,
-                                       const char *property_name,
-                                       unsigned char *mac_addr)
-{
-       struct device_node *np = of_find_node_by_path(node_name);
-       const char *mac_str = NULL;
-       int values[6] = {0};
-       unsigned char mac_temp[6] = {0};
-       int i, ret = 0;
-
-       if (!np)
-               return -EADDRNOTAVAIL;
-
-       /* If the property is present but contains an invalid value,
-        * then something is wrong. Log the error in that case.
-        */
-       if (of_property_read_string(np, property_name, &mac_str)) {
-               ret = -EADDRNOTAVAIL;
-               goto err_out;
-       }
-
-       /* The DTB property is a string of the form xx:xx:xx:xx:xx:xx
-        * Convert to an array of bytes.
-        */
-       if (sscanf(mac_str, "%x:%x:%x:%x:%x:%x",
-               &values[0], &values[1], &values[2],
-               &values[3], &values[4], &values[5]) != 6) {
-               ret = -EINVAL;
-               goto err_out;
-       }
-
-       for (i = 0; i < 6; ++i)
-               mac_temp[i] = (unsigned char)values[i];
-
-       if (!is_valid_ether_addr(mac_temp)) {
-               ret = -EINVAL;
-               goto err_out;
-       }
-
-       memcpy(mac_addr, mac_temp, 6);
-
-       of_node_put(np);
-
-       return ret;
-
-err_out:
-       DHD_ERROR(("%s: bad mac address at %s/%s: %s.\n",
-               __func__, node_name, property_name,
-               (mac_str) ? mac_str : "null"));
-
-       of_node_put(np);
-
-       return ret;
-}
-
 static int wifi_get_mac_addr(unsigned char *buf)
 {
-       /* try to get mac address stored in dtb chosen first and if that
-        * fails try filesystem.
-        */
-       if (_wifi_get_mac_address_dtb("/chosen", "nvidia,wifi-mac", buf))
-               return _wifi_get_mac_addr_file(buf);
+       struct device_node *dt_node;
+       const void *mac_addr;
+
+       dt_node = of_find_compatible_node(NULL, NULL, "android,bcmdhd_wlan");
+       if (!dt_node)
+               return -ENOENT;
+       mac_addr = of_get_mac_address(dt_node);
+       of_node_put(dt_node);
+       if (!mac_addr)
+               return -ENOENT;
+       memcpy(buf, mac_addr, 6);
+       pr_info("%s: %02x:%02x:%02x:%02x:%02x:%02x\n",
+               __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
 
        return 0;
 }
@@ -344,8 +246,7 @@ int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf)
 
        /* The MAC address search order is:
         * Userspace command (e.g. ifconfig)
-        * DTB (from NCT/EEPROM)
-        * File (FCT/rootfs)
+        * of_get_mac_address()
         * OTP
         */
        if (wifi_get_mac_addr(buf) == 0)
index ffab033..5cf7e3f 100644 (file)
@@ -55,6 +55,144 @@ const int of_get_phy_mode(struct device_node *np)
 }
 EXPORT_SYMBOL_GPL(of_get_phy_mode);
 
+static int _of_get_mac_addr_file(const char *filename, unsigned char *buf)
+{
+       struct file *fp;
+       int rdlen;
+       char str[32];
+       int mac[6];
+       int ret = 0;
+
+       /* open mac address file */
+       fp = filp_open(filename, O_RDONLY, 0);
+       if (IS_ERR(fp)) {
+               pr_debug("%s: cannot open %s\n",
+                       __FUNCTION__, filename);
+               return -ENOENT;
+       }
+
+       /* read mac address file */
+       memset(str, 0, sizeof(str));
+       rdlen = kernel_read(fp, fp->f_pos, str, 17);
+       if (rdlen > 0)
+               fp->f_pos += rdlen;
+       if (rdlen != 17) {
+               pr_debug("%s: bad mac address file"
+                       " - len %d < 17",
+                       __FUNCTION__, rdlen);
+               ret = -ENOENT;
+       } else if (sscanf(str, "%x:%x:%x:%x:%x:%x",
+               &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
+               pr_debug("%s: bad mac address file"
+                       " - must contain xx:xx:xx:xx:xx:xx\n",
+                       __FUNCTION__);
+               ret = -ENOENT;
+       } else {
+               pr_debug("%s: using mac %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       __FUNCTION__,
+                       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+               buf[0] = (unsigned char) mac[0];
+               buf[1] = (unsigned char) mac[1];
+               buf[2] = (unsigned char) mac[2];
+               buf[3] = (unsigned char) mac[3];
+               buf[4] = (unsigned char) mac[4];
+               buf[5] = (unsigned char) mac[5];
+               if (!is_valid_ether_addr(buf)) {
+                       pr_debug("%s: ignoring invalid mac\n",
+                               __FUNCTION__);
+                       ret = -EINVAL;
+               }
+       }
+
+       /* close mac address file */
+       filp_close(fp, NULL);
+
+       return ret;
+}
+
+/* Get MAC address from the specified DTB path */
+static int _of_get_mac_address_dtb(const char *node_name,
+                                       const char *property_name,
+                                       unsigned char *mac_addr)
+{
+       struct device_node *np = of_find_node_by_path(node_name);
+       const char *mac_str = NULL;
+       int values[6] = {0};
+       unsigned char mac_temp[6] = {0};
+       int i, ret = 0;
+
+       if (!np)
+               return -EADDRNOTAVAIL;
+
+       /* If the property is present but contains an invalid value,
+        * then something is wrong. Log the error in that case.
+        */
+       if (of_property_read_string(np, property_name, &mac_str)) {
+               ret = -EADDRNOTAVAIL;
+               goto err_out;
+       }
+
+       /* The DTB property is a string of the form xx:xx:xx:xx:xx:xx
+        * Convert to an array of bytes.
+        */
+       if (sscanf(mac_str, "%x:%x:%x:%x:%x:%x",
+               &values[0], &values[1], &values[2],
+               &values[3], &values[4], &values[5]) != 6) {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       for (i = 0; i < 6; ++i)
+               mac_temp[i] = (unsigned char)values[i];
+
+       if (!is_valid_ether_addr(mac_temp)) {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       memcpy(mac_addr, mac_temp, 6);
+
+       of_node_put(np);
+
+       return ret;
+
+err_out:
+       pr_err("%s: bad mac address at %s/%s: %s.\n",
+               __func__, node_name, property_name,
+               (mac_str) ? mac_str : "null");
+
+       of_node_put(np);
+
+       return ret;
+}
+
+static struct property *_of_set_mac_address(struct device_node *np,
+       unsigned char *mac_addr)
+{
+       struct property *prop;
+
+       /* allocate mac address property */
+       prop = kzalloc(sizeof(struct property) + 12 + 6, GFP_KERNEL);
+       if (!prop)
+               return NULL;
+       prop->name = ((char *) prop) + sizeof(struct property);
+       sprintf(prop->name, "mac-address");
+       prop->value = prop->name + strlen(prop->name) + 1;
+       memcpy(prop->value, mac_addr, 6);
+       prop->length = 6;
+       prop->next = NULL;
+
+       /* add mac address property */
+       if (of_add_property(np, prop)) {
+               pr_err("%s: failed to add property %s\n",
+                       __FUNCTION__, prop->name);
+               kfree(prop);
+               return NULL;
+       }
+
+       return prop;
+}
+
 /**
  * Search the device tree for the best MAC address to use.  'mac-address' is
  * checked first, because that is supposed to contain to "most recent" MAC
@@ -76,6 +214,9 @@ EXPORT_SYMBOL_GPL(of_get_phy_mode);
 const void *of_get_mac_address(struct device_node *np)
 {
        struct property *pp;
+       int err;
+       const char *s;
+       unsigned char mac_addr[6];
 
        pp = of_find_property(np, "mac-address", NULL);
        if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
@@ -89,6 +230,33 @@ const void *of_get_mac_address(struct device_node *np)
        if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value))
                return pp->value;
 
+       err = of_property_read_string(np, "mac-address-chosen-dtb-node", &s);
+       if (err == 0) {
+               pr_info("%s: checking /chosen dtb node for"
+                       " mac address property %s\n",
+                       __func__, s);
+               err = _of_get_mac_address_dtb("/chosen", s, mac_addr);
+               if (err == 0) {
+                       pp = _of_set_mac_address(np, mac_addr);
+                       if (pp && (pp->length == 6) &&
+                               is_valid_ether_addr(pp->value))
+                               return pp->value;
+               }
+       }
+
+       err = of_property_read_string(np, "mac-address-file", &s);
+       if (err == 0) {
+               pr_info("%s: checking file %s for mac address\n",
+                       __func__, s);
+               err = _of_get_mac_addr_file(s, mac_addr);
+               if (err == 0) {
+                       pp = _of_set_mac_address(np, mac_addr);
+                       if (pp && (pp->length == 6) &&
+                               is_valid_ether_addr(pp->value))
+                               return pp->value;
+               }
+       }
+
        return NULL;
 }
 EXPORT_SYMBOL(of_get_mac_address);