From d9a8fa86c0fcb9d2852f4ff581f3381d10ef450e Mon Sep 17 00:00:00 2001 From: Yuanyuan Liu Date: Thu, 1 Dec 2016 10:55:25 -0800 Subject: [PATCH] icnss: Add support of setting MAC address from platform driver Add support of setting WLAN MAC address from platform driver. The MAC address will be passed to WLAN driver when WLAN is turned on. CRs-Fixed: 1096286 Change-Id: I249222b419dd130241cbc84f4d41709b408941e0 Signed-off-by: Yuanyuan Liu --- drivers/soc/qcom/icnss.c | 83 ++++++++++++++++++++++++++++++++++++++++ include/soc/qcom/icnss.h | 3 ++ 2 files changed, 86 insertions(+) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 59d7f6423932..37204dcbc065 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -409,6 +410,12 @@ struct icnss_stats { uint32_t vbatt_req_err; }; +#define MAX_NO_OF_MAC_ADDR 4 +struct icnss_wlan_mac_addr { + u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN]; + uint32_t no_of_mac_addr_set; +}; + static struct icnss_priv { uint32_t magic; struct platform_device *pdev; @@ -466,6 +473,8 @@ static struct icnss_priv { uint64_t vph_pwr; atomic_t pm_count; struct ramdump_device *msa0_dump_dev; + bool is_wlan_mac_set; + struct icnss_wlan_mac_addr wlan_mac_addr; } *penv; static void icnss_hw_write_reg(void *base, u32 offset, u32 val) @@ -3548,6 +3557,80 @@ unsigned int icnss_socinfo_get_serial_number(struct device *dev) } EXPORT_SYMBOL(icnss_socinfo_get_serial_number); +int icnss_set_wlan_mac_address(struct device *dev, + const u8 *in, uint32_t len) +{ + struct icnss_priv *priv = dev_get_drvdata(dev); + uint32_t no_of_mac_addr; + struct icnss_wlan_mac_addr *addr = NULL; + int iter; + u8 *temp = NULL; + + if (priv->magic != ICNSS_MAGIC) { + icnss_pr_err("Invalid drvdata: dev %p, data %p, magic 0x%x\n", + dev, priv, priv->magic); + return -EINVAL; + } + + if (priv->is_wlan_mac_set) { + icnss_pr_dbg("WLAN MAC address is already set\n"); + return 0; + } + + if (len == 0 || (len % ETH_ALEN) != 0) { + icnss_pr_err("Invalid length %d\n", len); + return -EINVAL; + } + + no_of_mac_addr = len / ETH_ALEN; + if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) { + icnss_pr_err("Exceed maxinum supported MAC address %u %u\n", + MAX_NO_OF_MAC_ADDR, no_of_mac_addr); + return -EINVAL; + } + + priv->is_wlan_mac_set = true; + addr = &priv->wlan_mac_addr; + addr->no_of_mac_addr_set = no_of_mac_addr; + temp = &addr->mac_addr[0][0]; + + for (iter = 0; iter < no_of_mac_addr; + ++iter, temp += ETH_ALEN, in += ETH_ALEN) { + ether_addr_copy(temp, in); + icnss_pr_dbg("MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n", + temp[0], temp[1], temp[2], + temp[3], temp[4], temp[5]); + } + + return 0; +} +EXPORT_SYMBOL(icnss_set_wlan_mac_address); + +u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num) +{ + struct icnss_priv *priv = dev_get_drvdata(dev); + struct icnss_wlan_mac_addr *addr = NULL; + + if (priv->magic != ICNSS_MAGIC) { + icnss_pr_err("Invalid drvdata: dev %p, data %p, magic 0x%x\n", + dev, priv, priv->magic); + goto out; + } + + if (!priv->is_wlan_mac_set) { + icnss_pr_dbg("WLAN MAC address is not set\n"); + goto out; + } + + addr = &priv->wlan_mac_addr; + *num = addr->no_of_mac_addr_set; + return &addr->mac_addr[0][0]; +out: + *num = 0; + return NULL; +} +EXPORT_SYMBOL(icnss_get_wlan_mac_address); + static int icnss_smmu_init(struct icnss_priv *priv) { struct dma_iommu_mapping *mapping; diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 7e2f32883aa4..29990f036552 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -124,5 +124,8 @@ extern int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count, extern int icnss_wlan_set_dfs_nol(const void *info, u16 info_len); extern int icnss_wlan_get_dfs_nol(void *info, u16 info_len); extern bool icnss_is_qmi_disable(void); +extern int icnss_set_wlan_mac_address(struct device *dev, + const u8 *in, uint32_t len); +extern u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num); #endif /* _ICNSS_WLAN_H_ */