Commit 1476014f authored by Aloka Dixit's avatar Aloka Dixit Committed by Kalle Valo

wifi: ath12k: WMI support to process EHT capabilities

Add WMI support to process the EHT capabilities passed by
the firmware. Add required EHT specific definitions in
structures ath12k_band_cap and ath12k_wmi_svc_rdy_ext_parse.

For single_pdev chip such as WCN7850, only one pdev is created
and only one hardware is registered to mac80211. This one pdev
manages both 2.4 GHz radio and 5 GHz/6 GHz radio.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
Signed-off-by: default avatarAloka Dixit <quic_alokad@quicinc.com>
Co-developed-by: default avatarPradeep Kumar Chitrapu <quic_pradeepc@quicinc.com>
Signed-off-by: default avatarPradeep Kumar Chitrapu <quic_pradeepc@quicinc.com>
Co-developed-by: default avatarWen Gong <quic_wgong@quicinc.com>
Signed-off-by: default avatarWen Gong <quic_wgong@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20230725224034.14045-4-quic_alokad@quicinc.com
parent a7a6a45d
...@@ -580,6 +580,14 @@ struct ath12k_band_cap { ...@@ -580,6 +580,14 @@ struct ath12k_band_cap {
u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE]; u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE];
struct ath12k_wmi_ppe_threshold_arg he_ppet; struct ath12k_wmi_ppe_threshold_arg he_ppet;
u16 he_6ghz_capa; u16 he_6ghz_capa;
u32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE];
u32 eht_cap_phy_info[WMI_MAX_EHTCAP_PHY_SIZE];
u32 eht_mcs_20_only;
u32 eht_mcs_80;
u32 eht_mcs_160;
u32 eht_mcs_320;
struct ath12k_wmi_ppe_threshold_arg eht_ppet;
u32 eht_cap_info_internal;
}; };
struct ath12k_pdev_cap { struct ath12k_pdev_cap {
...@@ -614,6 +622,12 @@ struct ath12k_pdev { ...@@ -614,6 +622,12 @@ struct ath12k_pdev {
struct mlo_timestamp timestamp; struct mlo_timestamp timestamp;
}; };
struct ath12k_fw_pdev {
u32 pdev_id;
u32 phy_id;
u32 supported_bands;
};
struct ath12k_board_data { struct ath12k_board_data {
const struct firmware *fw; const struct firmware *fw;
const void *data; const void *data;
...@@ -669,7 +683,26 @@ struct ath12k_base { ...@@ -669,7 +683,26 @@ struct ath12k_base {
struct mutex core_lock; struct mutex core_lock;
/* Protects data like peers */ /* Protects data like peers */
spinlock_t base_lock; spinlock_t base_lock;
/* Single pdev device (struct ath12k_hw_params::single_pdev_only):
*
* Firmware maintains data for all bands but advertises a single
* phy to the host which is stored as a single element in this
* array.
*
* Other devices:
*
* This array will contain as many elements as the number of
* radios.
*/
struct ath12k_pdev pdevs[MAX_RADIOS]; struct ath12k_pdev pdevs[MAX_RADIOS];
/* struct ath12k_hw_params::single_pdev_only devices use this to
* store phy specific data
*/
struct ath12k_fw_pdev fw_pdev[MAX_RADIOS];
u8 fw_pdev_count;
struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS]; struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS];
struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS]; struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS];
unsigned long long free_vdev_map; unsigned long long free_vdev_map;
......
...@@ -65,6 +65,8 @@ struct ath12k_wmi_svc_rdy_ext_parse { ...@@ -65,6 +65,8 @@ struct ath12k_wmi_svc_rdy_ext_parse {
struct ath12k_wmi_svc_rdy_ext2_parse { struct ath12k_wmi_svc_rdy_ext2_parse {
struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse; struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse;
bool dma_ring_cap_done; bool dma_ring_cap_done;
bool spectral_bin_scaling_done;
bool mac_phy_caps_ext_done;
}; };
struct ath12k_wmi_rdy_parse { struct ath12k_wmi_rdy_parse {
...@@ -445,8 +447,10 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, ...@@ -445,8 +447,10 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps = svc->hw_caps; const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps = svc->hw_caps;
const struct ath12k_wmi_hw_mode_cap_params *wmi_hw_mode_caps = svc->hw_mode_caps; const struct ath12k_wmi_hw_mode_cap_params *wmi_hw_mode_caps = svc->hw_mode_caps;
const struct ath12k_wmi_mac_phy_caps_params *wmi_mac_phy_caps = svc->mac_phy_caps; const struct ath12k_wmi_mac_phy_caps_params *wmi_mac_phy_caps = svc->mac_phy_caps;
struct ath12k_base *ab = wmi_handle->wmi_ab->ab;
struct ath12k_band_cap *cap_band; struct ath12k_band_cap *cap_band;
struct ath12k_pdev_cap *pdev_cap = &pdev->cap; struct ath12k_pdev_cap *pdev_cap = &pdev->cap;
struct ath12k_fw_pdev *fw_pdev;
u32 phy_map; u32 phy_map;
u32 hw_idx, phy_idx = 0; u32 hw_idx, phy_idx = 0;
int i; int i;
...@@ -475,6 +479,12 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, ...@@ -475,6 +479,12 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands);
pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density); pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density);
fw_pdev = &ab->fw_pdev[ab->fw_pdev_count];
fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands);
fw_pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id);
fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id);
ab->fw_pdev_count++;
/* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from
* band to band for a single radio, need to see how this should be * band to band for a single radio, need to see how this should be
* handled. * handled.
...@@ -3815,6 +3825,7 @@ static int ath12k_wmi_ext_soc_hal_reg_caps_parse(struct ath12k_base *soc, ...@@ -3815,6 +3825,7 @@ static int ath12k_wmi_ext_soc_hal_reg_caps_parse(struct ath12k_base *soc,
soc->num_radios = 0; soc->num_radios = 0;
phy_id_map = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.phy_id_map); phy_id_map = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.phy_id_map);
soc->fw_pdev_count = 0;
while (phy_id_map && soc->num_radios < MAX_RADIOS) { while (phy_id_map && soc->num_radios < MAX_RADIOS) {
ret = ath12k_pull_mac_phy_cap_svc_ready_ext(wmi_handle, ret = ath12k_pull_mac_phy_cap_svc_ready_ext(wmi_handle,
...@@ -4042,6 +4053,125 @@ static int ath12k_service_ready_ext_event(struct ath12k_base *ab, ...@@ -4042,6 +4053,125 @@ static int ath12k_service_ready_ext_event(struct ath12k_base *ab,
return ret; return ret;
} }
static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band,
const __le32 cap_mac_info[],
const __le32 cap_phy_info[],
const __le32 supp_mcs[],
const struct ath12k_wmi_ppe_threshold_params *ppet,
__le32 cap_info_internal)
{
struct ath12k_band_cap *cap_band = &pdev->cap.band[band];
u8 i;
for (i = 0; i < WMI_MAX_EHTCAP_MAC_SIZE; i++)
cap_band->eht_cap_mac_info[i] = le32_to_cpu(cap_mac_info[i]);
for (i = 0; i < WMI_MAX_EHTCAP_PHY_SIZE; i++)
cap_band->eht_cap_phy_info[i] = le32_to_cpu(cap_phy_info[i]);
cap_band->eht_mcs_20_only = le32_to_cpu(supp_mcs[0]);
cap_band->eht_mcs_80 = le32_to_cpu(supp_mcs[1]);
if (band != NL80211_BAND_2GHZ) {
cap_band->eht_mcs_160 = le32_to_cpu(supp_mcs[2]);
cap_band->eht_mcs_320 = le32_to_cpu(supp_mcs[3]);
}
cap_band->eht_ppet.numss_m1 = le32_to_cpu(ppet->numss_m1);
cap_band->eht_ppet.ru_bit_mask = le32_to_cpu(ppet->ru_info);
for (i = 0; i < WMI_MAX_NUM_SS; i++)
cap_band->eht_ppet.ppet16_ppet8_ru3_ru0[i] =
le32_to_cpu(ppet->ppet16_ppet8_ru3_ru0[i]);
cap_band->eht_cap_info_internal = le32_to_cpu(cap_info_internal);
}
static int
ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab,
const struct ath12k_wmi_caps_ext_params *caps,
struct ath12k_pdev *pdev)
{
u32 bands;
int i;
if (ab->hw_params->single_pdev_only) {
for (i = 0; i < ab->fw_pdev_count; i++) {
struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i];
if (fw_pdev->pdev_id == le32_to_cpu(caps->pdev_id) &&
fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) {
bands = fw_pdev->supported_bands;
break;
}
}
if (i == ab->fw_pdev_count)
return -EINVAL;
} else {
bands = pdev->cap.supported_bands;
}
if (bands & WMI_HOST_WLAN_2G_CAP) {
ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_2GHZ,
caps->eht_cap_mac_info_2ghz,
caps->eht_cap_phy_info_2ghz,
caps->eht_supp_mcs_ext_2ghz,
&caps->eht_ppet_2ghz,
caps->eht_cap_info_internal);
}
if (bands & WMI_HOST_WLAN_5G_CAP) {
ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_5GHZ,
caps->eht_cap_mac_info_5ghz,
caps->eht_cap_phy_info_5ghz,
caps->eht_supp_mcs_ext_5ghz,
&caps->eht_ppet_5ghz,
caps->eht_cap_info_internal);
ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_6GHZ,
caps->eht_cap_mac_info_5ghz,
caps->eht_cap_phy_info_5ghz,
caps->eht_supp_mcs_ext_5ghz,
&caps->eht_ppet_5ghz,
caps->eht_cap_info_internal);
}
return 0;
}
static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag,
u16 len, const void *ptr,
void *data)
{
const struct ath12k_wmi_caps_ext_params *caps = ptr;
int i = 0, ret;
if (tag != WMI_TAG_MAC_PHY_CAPABILITIES_EXT)
return -EPROTO;
if (ab->hw_params->single_pdev_only) {
if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id))
return 0;
} else {
for (i = 0; i < ab->num_radios; i++) {
if (ab->pdevs[i].pdev_id == le32_to_cpu(caps->pdev_id))
break;
}
if (i == ab->num_radios)
return -EINVAL;
}
ret = ath12k_wmi_tlv_mac_phy_caps_ext_parse(ab, caps, &ab->pdevs[i]);
if (ret) {
ath12k_warn(ab,
"failed to parse extended MAC PHY capabilities for pdev %d: %d\n",
ret, ab->pdevs[i].pdev_id);
return ret;
}
return 0;
}
static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
u16 tag, u16 len, u16 tag, u16 len,
const void *ptr, void *data) const void *ptr, void *data)
...@@ -4058,6 +4188,23 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, ...@@ -4058,6 +4188,23 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
return ret; return ret;
parse->dma_ring_cap_done = true; parse->dma_ring_cap_done = true;
} else if (!parse->spectral_bin_scaling_done) {
/* TODO: This is a place-holder as WMI tag for
* spectral scaling is before
* WMI_TAG_MAC_PHY_CAPABILITIES_EXT
*/
parse->spectral_bin_scaling_done = true;
} else if (!parse->mac_phy_caps_ext_done) {
ret = ath12k_wmi_tlv_iter(ab, ptr, len,
ath12k_wmi_tlv_mac_phy_caps_ext,
parse);
if (ret) {
ath12k_warn(ab, "failed to parse extended MAC PHY capabilities WMI TLV: %d\n",
ret);
return ret;
}
parse->mac_phy_caps_ext_done = true;
} }
break; break;
default: default:
......
...@@ -2581,6 +2581,44 @@ struct ath12k_wmi_soc_hal_reg_caps_params { ...@@ -2581,6 +2581,44 @@ struct ath12k_wmi_soc_hal_reg_caps_params {
__le32 num_phy; __le32 num_phy;
} __packed; } __packed;
#define WMI_MAX_EHTCAP_MAC_SIZE 2
#define WMI_MAX_EHTCAP_PHY_SIZE 3
/* Used for EHT MCS-NSS array. Data at each array index follows the format given
* in IEEE P802.11be/D2.0, May 20229.4.2.313.4.
*
* Index interpretation:
* 0 - 20 MHz only sta, all 4 bytes valid
* 1 - index for bandwidths <= 80 MHz except 20 MHz-only, first 3 bytes valid
* 2 - index for 160 MHz, first 3 bytes valid
* 3 - index for 320 MHz, first 3 bytes valid
*/
#define WMI_MAX_EHT_SUPP_MCS_2G_SIZE 2
#define WMI_MAX_EHT_SUPP_MCS_5G_SIZE 4
struct ath12k_wmi_caps_ext_params {
__le32 hw_mode_id;
union {
struct {
__le16 pdev_id;
__le16 hw_link_id;
} __packed ath12k_wmi_pdev_to_link_map;
__le32 pdev_id;
};
__le32 phy_id;
__le32 wireless_modes_ext;
__le32 eht_cap_mac_info_2ghz[WMI_MAX_EHTCAP_MAC_SIZE];
__le32 eht_cap_mac_info_5ghz[WMI_MAX_EHTCAP_MAC_SIZE];
__le32 rsvd0[2];
__le32 eht_cap_phy_info_2ghz[WMI_MAX_EHTCAP_PHY_SIZE];
__le32 eht_cap_phy_info_5ghz[WMI_MAX_EHTCAP_PHY_SIZE];
struct ath12k_wmi_ppe_threshold_params eht_ppet_2ghz;
struct ath12k_wmi_ppe_threshold_params eht_ppet_5ghz;
__le32 eht_cap_info_internal;
__le32 eht_supp_mcs_ext_2ghz[WMI_MAX_EHT_SUPP_MCS_2G_SIZE];
__le32 eht_supp_mcs_ext_5ghz[WMI_MAX_EHT_SUPP_MCS_5G_SIZE];
} __packed;
/* 2 word representation of MAC addr */ /* 2 word representation of MAC addr */
struct ath12k_wmi_mac_addr_params { struct ath12k_wmi_mac_addr_params {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment