diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 871329c79a46..bdbc8d93c802 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1528,6 +1528,7 @@ static void ath10k_core_restart(struct work_struct *work) struct ath10k *ar = container_of(work, struct ath10k, restart_work); set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); + ath10k_gen_set_base_mac_addr(ar, ar->base_mac_addr); /* Place a barrier to make sure the compiler doesn't reorder * CRASH_FLUSH and calling other functions. diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 9310de85f2a0..f2f0338696e0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "htt.h" #include "htc.h" @@ -708,6 +709,7 @@ struct ath10k { struct ieee80211_ops *ops; struct device *dev; u8 mac_addr[ETH_ALEN]; + u8 base_mac_addr[ETH_ALEN]; enum ath10k_hw_rev hw_rev; u16 dev_id; diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 9817c89cd76d..129859255295 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -188,6 +188,9 @@ struct wmi_ops { u8 enable, u32 detect_level, u32 detect_margin); + struct sk_buff *(*gen_set_pdev_mac_addr)(struct ath10k *ar, u32 pdev_id, + u8 *mac_addr); + struct sk_buff *(*ext_resource_config)(struct ath10k *ar, enum wmi_host_platform_type type, u32 fw_feature_bitmap); @@ -1417,4 +1420,25 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value) return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid); } +static inline int +ath10k_gen_set_base_mac_addr(struct ath10k *ar, u8 *mac) +{ + struct sk_buff *skb; + int ret; + + if (!ar->wmi.ops->gen_set_pdev_mac_addr) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_set_pdev_mac_addr(ar, 0, mac); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_set_base_macaddr_cmdid); + if (ret) + return ret; + + return 0; +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index b0f3e9b9ef6f..de95e13a6036 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3173,6 +3173,33 @@ ath10k_wmi_tlv_op_gen_wow_del_pattern(struct ath10k *ar, u32 vdev_id, return skb; } +static struct sk_buff * +ath10k_wmi_tlv_op_gen_set_base_mac_addr(struct ath10k *ar, u32 pdev_id, + u8 *mac_addr) +{ + struct wmi_tlv_mac_addr_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + size_t len; + + len = sizeof(*tlv) + sizeof(*cmd); + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (struct wmi_tlv *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_BASE_MACADDR_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + + cmd->pdev_id = __cpu_to_le32(pdev_id); + ether_addr_copy(cmd->mac_addr.addr, mac_addr); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set_base_mac addr pdev_id %d mac addr %pM\n", + cmd->pdev_id, cmd->mac_addr.addr); + return skb; +} + static struct sk_buff * ath10k_wmi_tlv_op_gen_adaptive_qcs(struct ath10k *ar, bool enable) { @@ -3719,6 +3746,7 @@ static const struct wmi_ops wmi_hl_1_0_ops = { .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, + .gen_set_pdev_mac_addr = ath10k_wmi_tlv_op_gen_set_base_mac_addr, }; void ath10k_wmi_hl_1_0_attach(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 2b8318010a35..31f34b43e381 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1849,4 +1849,9 @@ struct wmi_tlv_mgmt_tx_cmd { __le16 data_tag; u8 buf[0]; } __packed; + +struct wmi_tlv_mac_addr_cmd { + __le32 pdev_id; + struct wmi_mac_addr mac_addr; +} __packed; #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f7ada7147136..2ce61e64c82e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4844,6 +4844,39 @@ static int ath10k_wmi_op_pull_echo_ev(struct ath10k *ar, return 0; } +void +ath10k_generate_mac_addr_auto(struct ath10k *ar, struct wmi_rdy_ev_arg *arg) +{ + unsigned int soc_serial_num; + u8 bdata_mac_addr[ETH_ALEN]; + u8 udef_mac_addr[] = {0x00, 0x0A, 0xF5, 0x00, 0x00, 0x00}; + + soc_serial_num = socinfo_get_serial_number(); + if (!soc_serial_num) + return; + + if (arg->mac_addr) { + ether_addr_copy(ar->base_mac_addr, arg->mac_addr); + ether_addr_copy(bdata_mac_addr, arg->mac_addr); + soc_serial_num &= 0x00ffffff; + bdata_mac_addr[3] = (soc_serial_num >> 16) & 0xff; + bdata_mac_addr[4] = (soc_serial_num >> 8) & 0xff; + bdata_mac_addr[5] = soc_serial_num & 0xff; + ether_addr_copy(ar->mac_addr, bdata_mac_addr); + } else { + /* If mac address not encoded in wlan board data, + * Auto-generate mac address using device serial + * number and user defined mac address 'udef_mac_addr'. + */ + udef_mac_addr[3] = (soc_serial_num >> 16) & 0xff; + udef_mac_addr[4] = (soc_serial_num >> 8) & 0xff; + udef_mac_addr[5] = soc_serial_num & 0xff; + ether_addr_copy(ar->base_mac_addr, udef_mac_addr); + udef_mac_addr[2] = (soc_serial_num >> 24) & 0xff; + ether_addr_copy(ar->mac_addr, udef_mac_addr); + } +} + int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) { struct wmi_rdy_ev_arg arg = {}; @@ -4862,7 +4895,11 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) arg.mac_addr, __le32_to_cpu(arg.status)); - ether_addr_copy(ar->mac_addr, arg.mac_addr); + if (QCA_REV_WCN3990(ar)) + ath10k_generate_mac_addr_auto(ar, &arg); + else + ether_addr_copy(ar->mac_addr, arg.mac_addr); + complete(&ar->wmi.unified_ready); return 0; }