// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
/* set the default max assoc sta to max supported by driver */
uint max_assoc_sta = WIL6210_MAX_CID;
module_param(max_assoc_sta, uint, 0444);
MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
int agg_wsize; /* = 0; */
module_param(agg_wsize, int, 0644);
MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;" " 0 - use default; < 0 - don't auto-establish");
u8 led_id = WIL_LED_INVALID_ID;
module_param(led_id, byte, 0444);
MODULE_PARM_DESC(led_id, " 60G device led enablement. Set the led ID (0-2) to enable");
/** * DOC: WMI event receiving - theory of operations * * When firmware about to report WMI event, it fills memory area * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler. * * @wmi_recv_cmd reads event, allocates memory chunk and attaches it to the * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up * and handles events within the @wmi_event_worker. Every event get detached * from list, processed and deleted. * * Purpose for this mechanism is to release IRQ thread; otherwise, * if WMI event handling involves another WMI command flow, this 2-nd flow * won't be completed because of blocked IRQ thread.
*/
/** * DOC: Addressing - theory of operations * * There are several buses present on the WIL6210 card. * Same memory areas are visible at different address on * the different buses. There are 3 main bus masters: * - MAC CPU (ucode) * - User CPU (firmware) * - AHB (host) * * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing * AHB addresses starting from 0x880000 * * Internally, firmware uses addresses that allow faster access but * are invisible from the host. To read from these addresses, alternative * AHB address must be used.
*/
/* sparrow_fw_mapping provides memory remapping table for sparrow * * array size should be in sync with the declaration in the wil6210.h * * Sparrow memory mapping: * Linker address PCI/Host address * 0x880000 .. 0xa80000 2Mb BAR0 * 0x800000 .. 0x808000 0x900000 .. 0x908000 32k DCCM * 0x840000 .. 0x860000 0x908000 .. 0x928000 128k PERIPH
*/ conststruct fw_map sparrow_fw_mapping[] = { /* FW code RAM 256k */
{0x000000, 0x040000, 0x8c0000, "fw_code", true, true}, /* FW data RAM 32k */
{0x800000, 0x808000, 0x900000, "fw_data", true, true}, /* periph data 128k */
{0x840000, 0x860000, 0x908000, "fw_peri", true, true}, /* various RGF 40k */
{0x880000, 0x88a000, 0x880000, "rgf", true, true}, /* AGC table 4k */
{0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true, true}, /* Pcie_ext_rgf 4k */
{0x88b000, 0x88c000, 0x88b000, "rgf_ext", true, true}, /* mac_ext_rgf 512b */
{0x88c000, 0x88c200, 0x88c000, "mac_rgf_ext", true, true}, /* upper area 548k */
{0x8c0000, 0x949000, 0x8c0000, "upper", true, true}, /* UCODE areas - accessible by debugfs blobs but not by * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
*/ /* ucode code RAM 128k */
{0x000000, 0x020000, 0x920000, "uc_code", false, false}, /* ucode data RAM 16k */
{0x800000, 0x804000, 0x940000, "uc_data", false, false},
};
/* sparrow_d0_mac_rgf_ext - mac_rgf_ext section for Sparrow D0 * it is a bit larger to support extra features
*/ conststruct fw_map sparrow_d0_mac_rgf_ext = {
0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true, true
};
struct auth_no_hdr {
__le16 auth_alg;
__le16 auth_transaction;
__le16 status_code; /* possibly followed by Challenge text */
u8 variable[];
} __packed;
u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
/** * wmi_addr_remap - return AHB address for given firmware internal (linker) address * @x: internal address * If address have no valid AHB mapping, return 0
*/ static u32 wmi_addr_remap(u32 x)
{
uint i;
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { if (fw_mapping[i].fw &&
((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))) return x + fw_mapping[i].host - fw_mapping[i].from;
}
return 0;
}
/** * wil_find_fw_mapping - find fw_mapping entry by section name * @section: section name * * Return pointer to section or NULL if not found
*/ struct fw_map *wil_find_fw_mapping(constchar *section)
{ int i;
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) if (fw_mapping[i].name &&
!strcmp(section, fw_mapping[i].name)) return &fw_mapping[i];
return NULL;
}
/** * wmi_buffer_block - Check address validity for WMI buffer; remap if needed * @wil: driver data * @ptr_: internal (linker) fw/ucode address * @size: if non zero, validate the block does not * exceed the device memory (bar) * * Valid buffer should be DWORD aligned * * return address for accessing buffer from the host; * if buffer is not valid, return NULL.
*/ void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
{
u32 off;
u32 ptr = le32_to_cpu(ptr_);
if (ptr % 4) return NULL;
ptr = wmi_addr_remap(ptr); if (ptr < WIL6210_FW_HOST_OFF) return NULL;
off = HOSTADDR(ptr); if (off > wil->bar_size - 4) return NULL; if (size && ((off + size > wil->bar_size) || (off + size < off))) return NULL;
staticconstchar *cmdid2name(u16 cmdid)
{ switch (cmdid) { case WMI_NOTIFY_REQ_CMDID: return"WMI_NOTIFY_REQ_CMD"; case WMI_START_SCAN_CMDID: return"WMI_START_SCAN_CMD"; case WMI_CONNECT_CMDID: return"WMI_CONNECT_CMD"; case WMI_DISCONNECT_CMDID: return"WMI_DISCONNECT_CMD"; case WMI_SW_TX_REQ_CMDID: return"WMI_SW_TX_REQ_CMD"; case WMI_GET_RF_SECTOR_PARAMS_CMDID: return"WMI_GET_RF_SECTOR_PARAMS_CMD"; case WMI_SET_RF_SECTOR_PARAMS_CMDID: return"WMI_SET_RF_SECTOR_PARAMS_CMD"; case WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID: return"WMI_GET_SELECTED_RF_SECTOR_INDEX_CMD"; case WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID: return"WMI_SET_SELECTED_RF_SECTOR_INDEX_CMD"; case WMI_BRP_SET_ANT_LIMIT_CMDID: return"WMI_BRP_SET_ANT_LIMIT_CMD"; case WMI_TOF_SESSION_START_CMDID: return"WMI_TOF_SESSION_START_CMD"; case WMI_AOA_MEAS_CMDID: return"WMI_AOA_MEAS_CMD"; case WMI_PMC_CMDID: return"WMI_PMC_CMD"; case WMI_TOF_GET_TX_RX_OFFSET_CMDID: return"WMI_TOF_GET_TX_RX_OFFSET_CMD"; case WMI_TOF_SET_TX_RX_OFFSET_CMDID: return"WMI_TOF_SET_TX_RX_OFFSET_CMD"; case WMI_VRING_CFG_CMDID: return"WMI_VRING_CFG_CMD"; case WMI_BCAST_VRING_CFG_CMDID: return"WMI_BCAST_VRING_CFG_CMD"; case WMI_TRAFFIC_SUSPEND_CMDID: return"WMI_TRAFFIC_SUSPEND_CMD"; case WMI_TRAFFIC_RESUME_CMDID: return"WMI_TRAFFIC_RESUME_CMD"; case WMI_ECHO_CMDID: return"WMI_ECHO_CMD"; case WMI_SET_MAC_ADDRESS_CMDID: return"WMI_SET_MAC_ADDRESS_CMD"; case WMI_LED_CFG_CMDID: return"WMI_LED_CFG_CMD"; case WMI_PCP_START_CMDID: return"WMI_PCP_START_CMD"; case WMI_PCP_STOP_CMDID: return"WMI_PCP_STOP_CMD"; case WMI_SET_SSID_CMDID: return"WMI_SET_SSID_CMD"; case WMI_GET_SSID_CMDID: return"WMI_GET_SSID_CMD"; case WMI_SET_PCP_CHANNEL_CMDID: return"WMI_SET_PCP_CHANNEL_CMD"; case WMI_GET_PCP_CHANNEL_CMDID: return"WMI_GET_PCP_CHANNEL_CMD"; case WMI_P2P_CFG_CMDID: return"WMI_P2P_CFG_CMD"; case WMI_PORT_ALLOCATE_CMDID: return"WMI_PORT_ALLOCATE_CMD"; case WMI_PORT_DELETE_CMDID: return"WMI_PORT_DELETE_CMD"; case WMI_START_LISTEN_CMDID: return"WMI_START_LISTEN_CMD"; case WMI_START_SEARCH_CMDID: return"WMI_START_SEARCH_CMD"; case WMI_DISCOVERY_STOP_CMDID: return"WMI_DISCOVERY_STOP_CMD"; case WMI_DELETE_CIPHER_KEY_CMDID: return"WMI_DELETE_CIPHER_KEY_CMD"; case WMI_ADD_CIPHER_KEY_CMDID: return"WMI_ADD_CIPHER_KEY_CMD"; case WMI_SET_APPIE_CMDID: return"WMI_SET_APPIE_CMD"; case WMI_CFG_RX_CHAIN_CMDID: return"WMI_CFG_RX_CHAIN_CMD"; case WMI_TEMP_SENSE_CMDID: return"WMI_TEMP_SENSE_CMD"; case WMI_DEL_STA_CMDID: return"WMI_DEL_STA_CMD"; case WMI_DISCONNECT_STA_CMDID: return"WMI_DISCONNECT_STA_CMD"; case WMI_RING_BA_EN_CMDID: return"WMI_RING_BA_EN_CMD"; case WMI_RING_BA_DIS_CMDID: return"WMI_RING_BA_DIS_CMD"; case WMI_RCP_DELBA_CMDID: return"WMI_RCP_DELBA_CMD"; case WMI_RCP_ADDBA_RESP_CMDID: return"WMI_RCP_ADDBA_RESP_CMD"; case WMI_RCP_ADDBA_RESP_EDMA_CMDID: return"WMI_RCP_ADDBA_RESP_EDMA_CMD"; case WMI_PS_DEV_PROFILE_CFG_CMDID: return"WMI_PS_DEV_PROFILE_CFG_CMD"; case WMI_SET_MGMT_RETRY_LIMIT_CMDID: return"WMI_SET_MGMT_RETRY_LIMIT_CMD"; case WMI_GET_MGMT_RETRY_LIMIT_CMDID: return"WMI_GET_MGMT_RETRY_LIMIT_CMD"; case WMI_ABORT_SCAN_CMDID: return"WMI_ABORT_SCAN_CMD"; case WMI_NEW_STA_CMDID: return"WMI_NEW_STA_CMD"; case WMI_SET_THERMAL_THROTTLING_CFG_CMDID: return"WMI_SET_THERMAL_THROTTLING_CFG_CMD"; case WMI_GET_THERMAL_THROTTLING_CFG_CMDID: return"WMI_GET_THERMAL_THROTTLING_CFG_CMD"; case WMI_LINK_MAINTAIN_CFG_WRITE_CMDID: return"WMI_LINK_MAINTAIN_CFG_WRITE_CMD"; case WMI_LO_POWER_CALIB_FROM_OTP_CMDID: return"WMI_LO_POWER_CALIB_FROM_OTP_CMD"; case WMI_START_SCHED_SCAN_CMDID: return"WMI_START_SCHED_SCAN_CMD"; case WMI_STOP_SCHED_SCAN_CMDID: return"WMI_STOP_SCHED_SCAN_CMD"; case WMI_TX_STATUS_RING_ADD_CMDID: return"WMI_TX_STATUS_RING_ADD_CMD"; case WMI_RX_STATUS_RING_ADD_CMDID: return"WMI_RX_STATUS_RING_ADD_CMD"; case WMI_TX_DESC_RING_ADD_CMDID: return"WMI_TX_DESC_RING_ADD_CMD"; case WMI_RX_DESC_RING_ADD_CMDID: return"WMI_RX_DESC_RING_ADD_CMD"; case WMI_BCAST_DESC_RING_ADD_CMDID: return"WMI_BCAST_DESC_RING_ADD_CMD"; case WMI_CFG_DEF_RX_OFFLOAD_CMDID: return"WMI_CFG_DEF_RX_OFFLOAD_CMD"; case WMI_LINK_STATS_CMDID: return"WMI_LINK_STATS_CMD"; case WMI_SW_TX_REQ_EXT_CMDID: return"WMI_SW_TX_REQ_EXT_CMDID"; case WMI_FT_AUTH_CMDID: return"WMI_FT_AUTH_CMD"; case WMI_FT_REASSOC_CMDID: return"WMI_FT_REASSOC_CMD"; case WMI_UPDATE_FT_IES_CMDID: return"WMI_UPDATE_FT_IES_CMD"; case WMI_RBUFCAP_CFG_CMDID: return"WMI_RBUFCAP_CFG_CMD"; case WMI_TEMP_SENSE_ALL_CMDID: return"WMI_TEMP_SENSE_ALL_CMDID"; case WMI_SET_LINK_MONITOR_CMDID: return"WMI_SET_LINK_MONITOR_CMD"; default: return"Untracked CMD";
}
}
staticconstchar *eventid2name(u16 eventid)
{ switch (eventid) { case WMI_NOTIFY_REQ_DONE_EVENTID: return"WMI_NOTIFY_REQ_DONE_EVENT"; case WMI_DISCONNECT_EVENTID: return"WMI_DISCONNECT_EVENT"; case WMI_SW_TX_COMPLETE_EVENTID: return"WMI_SW_TX_COMPLETE_EVENT"; case WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID: return"WMI_GET_RF_SECTOR_PARAMS_DONE_EVENT"; case WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID: return"WMI_SET_RF_SECTOR_PARAMS_DONE_EVENT"; case WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID: return"WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT"; case WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID: return"WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENT"; case WMI_BRP_SET_ANT_LIMIT_EVENTID: return"WMI_BRP_SET_ANT_LIMIT_EVENT"; case WMI_FW_READY_EVENTID: return"WMI_FW_READY_EVENT"; case WMI_TRAFFIC_RESUME_EVENTID: return"WMI_TRAFFIC_RESUME_EVENT"; case WMI_TOF_GET_TX_RX_OFFSET_EVENTID: return"WMI_TOF_GET_TX_RX_OFFSET_EVENT"; case WMI_TOF_SET_TX_RX_OFFSET_EVENTID: return"WMI_TOF_SET_TX_RX_OFFSET_EVENT"; case WMI_VRING_CFG_DONE_EVENTID: return"WMI_VRING_CFG_DONE_EVENT"; case WMI_READY_EVENTID: return"WMI_READY_EVENT"; case WMI_RX_MGMT_PACKET_EVENTID: return"WMI_RX_MGMT_PACKET_EVENT"; case WMI_TX_MGMT_PACKET_EVENTID: return"WMI_TX_MGMT_PACKET_EVENT"; case WMI_SCAN_COMPLETE_EVENTID: return"WMI_SCAN_COMPLETE_EVENT"; case WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID: return"WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENT"; case WMI_CONNECT_EVENTID: return"WMI_CONNECT_EVENT"; case WMI_EAPOL_RX_EVENTID: return"WMI_EAPOL_RX_EVENT"; case WMI_BA_STATUS_EVENTID: return"WMI_BA_STATUS_EVENT"; case WMI_RCP_ADDBA_REQ_EVENTID: return"WMI_RCP_ADDBA_REQ_EVENT"; case WMI_DELBA_EVENTID: return"WMI_DELBA_EVENT"; case WMI_RING_EN_EVENTID: return"WMI_RING_EN_EVENT"; case WMI_DATA_PORT_OPEN_EVENTID: return"WMI_DATA_PORT_OPEN_EVENT"; case WMI_AOA_MEAS_EVENTID: return"WMI_AOA_MEAS_EVENT"; case WMI_TOF_SESSION_END_EVENTID: return"WMI_TOF_SESSION_END_EVENT"; case WMI_TOF_GET_CAPABILITIES_EVENTID: return"WMI_TOF_GET_CAPABILITIES_EVENT"; case WMI_TOF_SET_LCR_EVENTID: return"WMI_TOF_SET_LCR_EVENT"; case WMI_TOF_SET_LCI_EVENTID: return"WMI_TOF_SET_LCI_EVENT"; case WMI_TOF_FTM_PER_DEST_RES_EVENTID: return"WMI_TOF_FTM_PER_DEST_RES_EVENT"; case WMI_TOF_CHANNEL_INFO_EVENTID: return"WMI_TOF_CHANNEL_INFO_EVENT"; case WMI_TRAFFIC_SUSPEND_EVENTID: return"WMI_TRAFFIC_SUSPEND_EVENT"; case WMI_ECHO_RSP_EVENTID: return"WMI_ECHO_RSP_EVENT"; case WMI_LED_CFG_DONE_EVENTID: return"WMI_LED_CFG_DONE_EVENT"; case WMI_PCP_STARTED_EVENTID: return"WMI_PCP_STARTED_EVENT"; case WMI_PCP_STOPPED_EVENTID: return"WMI_PCP_STOPPED_EVENT"; case WMI_GET_SSID_EVENTID: return"WMI_GET_SSID_EVENT"; case WMI_GET_PCP_CHANNEL_EVENTID: return"WMI_GET_PCP_CHANNEL_EVENT"; case WMI_P2P_CFG_DONE_EVENTID: return"WMI_P2P_CFG_DONE_EVENT"; case WMI_PORT_ALLOCATED_EVENTID: return"WMI_PORT_ALLOCATED_EVENT"; case WMI_PORT_DELETED_EVENTID: return"WMI_PORT_DELETED_EVENT"; case WMI_LISTEN_STARTED_EVENTID: return"WMI_LISTEN_STARTED_EVENT"; case WMI_SEARCH_STARTED_EVENTID: return"WMI_SEARCH_STARTED_EVENT"; case WMI_DISCOVERY_STOPPED_EVENTID: return"WMI_DISCOVERY_STOPPED_EVENT"; case WMI_CFG_RX_CHAIN_DONE_EVENTID: return"WMI_CFG_RX_CHAIN_DONE_EVENT"; case WMI_TEMP_SENSE_DONE_EVENTID: return"WMI_TEMP_SENSE_DONE_EVENT"; case WMI_RCP_ADDBA_RESP_SENT_EVENTID: return"WMI_RCP_ADDBA_RESP_SENT_EVENT"; case WMI_PS_DEV_PROFILE_CFG_EVENTID: return"WMI_PS_DEV_PROFILE_CFG_EVENT"; case WMI_SET_MGMT_RETRY_LIMIT_EVENTID: return"WMI_SET_MGMT_RETRY_LIMIT_EVENT"; case WMI_GET_MGMT_RETRY_LIMIT_EVENTID: return"WMI_GET_MGMT_RETRY_LIMIT_EVENT"; case WMI_SET_THERMAL_THROTTLING_CFG_EVENTID: return"WMI_SET_THERMAL_THROTTLING_CFG_EVENT"; case WMI_GET_THERMAL_THROTTLING_CFG_EVENTID: return"WMI_GET_THERMAL_THROTTLING_CFG_EVENT"; case WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID: return"WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENT"; case WMI_LO_POWER_CALIB_FROM_OTP_EVENTID: return"WMI_LO_POWER_CALIB_FROM_OTP_EVENT"; case WMI_START_SCHED_SCAN_EVENTID: return"WMI_START_SCHED_SCAN_EVENT"; case WMI_STOP_SCHED_SCAN_EVENTID: return"WMI_STOP_SCHED_SCAN_EVENT"; case WMI_SCHED_SCAN_RESULT_EVENTID: return"WMI_SCHED_SCAN_RESULT_EVENT"; case WMI_TX_STATUS_RING_CFG_DONE_EVENTID: return"WMI_TX_STATUS_RING_CFG_DONE_EVENT"; case WMI_RX_STATUS_RING_CFG_DONE_EVENTID: return"WMI_RX_STATUS_RING_CFG_DONE_EVENT"; case WMI_TX_DESC_RING_CFG_DONE_EVENTID: return"WMI_TX_DESC_RING_CFG_DONE_EVENT"; case WMI_RX_DESC_RING_CFG_DONE_EVENTID: return"WMI_RX_DESC_RING_CFG_DONE_EVENT"; case WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID: return"WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENT"; case WMI_LINK_STATS_CONFIG_DONE_EVENTID: return"WMI_LINK_STATS_CONFIG_DONE_EVENT"; case WMI_LINK_STATS_EVENTID: return"WMI_LINK_STATS_EVENT"; case WMI_COMMAND_NOT_SUPPORTED_EVENTID: return"WMI_COMMAND_NOT_SUPPORTED_EVENT"; case WMI_FT_AUTH_STATUS_EVENTID: return"WMI_FT_AUTH_STATUS_EVENT"; case WMI_FT_REASSOC_STATUS_EVENTID: return"WMI_FT_REASSOC_STATUS_EVENT"; case WMI_RBUFCAP_CFG_EVENTID: return"WMI_RBUFCAP_CFG_EVENT"; case WMI_TEMP_SENSE_ALL_DONE_EVENTID: return"WMI_TEMP_SENSE_ALL_DONE_EVENTID"; case WMI_SET_LINK_MONITOR_EVENTID: return"WMI_SET_LINK_MONITOR_EVENT"; case WMI_LINK_MONITOR_EVENTID: return"WMI_LINK_MONITOR_EVENT"; default: return"Untracked EVENT";
}
}
wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n",
wil->fw_version, le32_to_cpu(evt->sw_version),
evt->mac, evt->numof_additional_mids); if (evt->numof_additional_mids + 1 < wil->max_vifs) {
wil_err(wil, "FW does not support enough MIDs (need %d)",
wil->max_vifs - 1); return; /* FW load will fail after timeout */
} /* ignore MAC address, we already have it from the boot loader */
strscpy(wiphy->fw_version, wil->fw_version, sizeof(wiphy->fw_version));
if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) {
wil_dbg_wmi(wil, "rfc calibration result %d\n",
evt->rfc_read_calib_result);
wil->fw_calib_result = evt->rfc_read_calib_result;
}
fw_max_assoc_sta = WIL6210_RX_DESC_MAX_CID; if (len > offsetof(struct wmi_ready_event, max_assoc_sta) &&
evt->max_assoc_sta > 0) {
fw_max_assoc_sta = evt->max_assoc_sta;
wil_dbg_wmi(wil, "fw reported max assoc sta %d\n",
fw_max_assoc_sta);
if (fw_max_assoc_sta > WIL6210_MAX_CID) {
wil_dbg_wmi(wil, "fw max assoc sta %d exceeds max driver supported %d\n",
fw_max_assoc_sta, WIL6210_MAX_CID);
fw_max_assoc_sta = WIL6210_MAX_CID;
}
}
wil->max_assoc_sta = min_t(uint, max_assoc_sta, fw_max_assoc_sta);
wil_dbg_wmi(wil, "setting max assoc sta to %d\n", wil->max_assoc_sta);
wil_set_recovery_state(wil, fw_recovery_idle);
set_bit(wil_status_fwready, wil->status); /* let the reset sequence continue */
complete(&wil->wmi_ready);
}
if (test_bit(wil_status_resetting, wil->status) ||
!test_bit(wil_status_fwready, wil->status)) {
wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
evt->cid); /* no need for cleanup, wil_reset will do that */ return;
}
mutex_lock(&wil->mutex);
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { if (!test_bit(wil_vif_fwconnecting, vif->status)) {
wil_err(wil, "Not in connecting state\n");
mutex_unlock(&wil->mutex); return;
}
timer_delete_sync(&vif->connect_timer);
} elseif ((wdev->iftype == NL80211_IFTYPE_AP) ||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) { if (wil->sta[evt->cid].status != wil_sta_unused) {
wil_err(wil, "AP: Invalid status %d for CID %d\n",
wil->sta[evt->cid].status, evt->cid);
mutex_unlock(&wil->mutex); return;
}
}
if (test_bit(wil_status_resetting, wil->status) ||
!test_bit(wil_status_fwready, wil->status)) {
wil_err(wil, "status_resetting, cancel disconnect event\n"); /* no need for cleanup, wil_reset will do that */ return;
}
/* disconnect event in disable_ap_sme mode means link loss */ switch (wdev->iftype) { /* AP-like interface */ case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: /* notify hostapd about link loss */
cfg80211_cqm_pktloss_notify(ndev, evt->bssid, 0,
GFP_KERNEL); break; default: break;
}
}
mutex_unlock(&wil->mutex);
}
/* * Firmware reports EAPOL frame using WME event. * Reconstruct Ethernet frame and deliver it via normal Rx
*/ staticvoid wmi_evt_eapol_rx(struct wil6210_vif *vif, int id, void *d, int len)
{ struct wil6210_priv *wil = vif_to_wil(vif); struct net_device *ndev = vif_to_ndev(vif); struct wmi_eapol_rx_event *evt = d;
u16 eapol_len = le16_to_cpu(evt->eapol_len); int sz = eapol_len + ETH_HLEN; struct sk_buff *skb; struct ethhdr *eth; int cid; struct wil_net_stats *stats = NULL;
wil_dbg_wmi(wil, "EAPOL len %d from %pM MID %d\n", eapol_len,
evt->src_mac, vif->mid);
if (vri >= ARRAY_SIZE(wil->ring_tx)) {
wil_err(wil, "Enable for invalid vring %d\n", vri); return;
}
if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme ||
test_bit(wil_vif_ft_roam, vif->status)) /* in AP mode with disable_ap_sme that is not FT, * this is done by wil_cfg80211_change_station()
*/
wil->ring_tx_data[vri].dot1x_open = true; if (vri == vif->bcast_ring) /* no BA for bcast */ return;
cid = wil->ring2cid_tid[vri][0]; if (!wil_cid_valid(wil, cid)) {
wil_err(wil, "invalid cid %d for vring %d\n", cid, vri); return;
}
/* In FT mode we get key but not store it as it is received * before WMI_CONNECT_EVENT received from FW. * wil_set_crypto_rx is called here to reset the security PN
*/
sta = &wil->sta[cid]; if (test_bit(wil_vif_ft_roam, vif->status)) {
memset(¶ms, 0, sizeof(params));
wil_set_crypto_rx(0, WMI_KEY_USE_PAIRWISE, sta, ¶ms); if (wdev->iftype != NL80211_IFTYPE_AP)
clear_bit(wil_vif_ft_roam, vif->status);
}
if (agg_wsize >= 0)
wil_addba_tx_request(wil, vri, agg_wsize);
}
/* find cid and ringid for the station vif * * return error, if other interfaces are used or ring was not found
*/ staticint wil_find_cid_ringid_sta(struct wil6210_priv *wil, struct wil6210_vif *vif, int *cid, int *ringid)
{ struct wil_ring *ring; struct wil_ring_tx_data *txdata; int min_ring_id = wil_get_min_tx_ring_id(wil); int i;
u8 lcid;
if (!(vif->wdev.iftype == NL80211_IFTYPE_STATION ||
vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
wil_err(wil, "invalid interface type %d\n", vif->wdev.iftype); return -EINVAL;
}
/* In the STA mode, it is expected to have only one ring * for the AP we are connected to. * find it and return the cid associated with it.
*/ for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
ring = &wil->ring_tx[i];
txdata = &wil->ring_tx_data[i]; if (!ring->va || !txdata->enabled || txdata->mid != vif->mid) continue;
if (test_bit(wil_status_resetting, wil->status) ||
!test_bit(wil_status_fwready, wil->status)) {
wil_err(wil, "FT: status_resetting, cancel reassoc event\n"); /* no need for cleanup, wil_reset will do that */ return;
}
mutex_lock(&wil->mutex);
/* ring modify to set the ring for the roamed AP settings */
wil_dbg_wmi(wil, "ft modify tx config for connection CID %d ring %d\n",
cid, ringid);
rc = wil->txrx_ops.tx_ring_modify(vif, ringid, cid, 0); if (rc) {
wil_err(wil, "modify TX for CID %d MID %d ring %d failed (%d)\n",
cid, vif->mid, ringid, rc);
mutex_unlock(&wil->mutex); goto fail;
}
/* Update the driver STA members with the new bss */
wil->sta[cid].aid = data->aid;
wil->sta[cid].stats.ft_roams++;
ether_addr_copy(wil->sta[cid].addr, vif->bss->bssid);
mutex_unlock(&wil->mutex);
timer_delete_sync(&vif->connect_timer);
/* Some events are ignored for purpose; and need not be interpreted as * "unhandled events"
*/ staticvoid wmi_evt_ignore(struct wil6210_vif *vif, int id, void *d, int len)
{ struct wil6210_priv *wil = vif_to_wil(vif);
wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len);
}
/* * Run in IRQ context * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev * that will be eventually handled by the @wmi_event_worker in the thread * context of thread "wil6210_wmi"
*/ void wmi_recv_cmd(struct wil6210_priv *wil)
{ struct wil6210_mbox_ring_desc d_tail; struct wil6210_mbox_hdr hdr; struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx; struct pending_wmi_event *evt;
u8 *cmd; void __iomem *src;
ulong flags; unsigned n; unsignedint num_immed_reply = 0;
if (!test_bit(wil_status_mbox_ready, wil->status)) {
wil_err(wil, "Reset in progress. Cannot handle WMI event\n"); return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.