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_ */