diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index b612cdfc5a31..d172e753de11 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1551,8 +1551,14 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = wmi_send(wil, WMI_CONNECT_CMDID, vif->mid, &conn, sizeof(conn)); if (rc == 0) { netif_carrier_on(ndev); - if (!wil_has_other_active_ifaces(wil, ndev, false, true)) - wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); + if (!wil_has_other_active_ifaces(wil, ndev, false, true)) { + if (wil->force_edmg_channel) + wil6210_bus_request(wil, + WIL_11AY_BUS_REQUEST_KBPS); + else + wil6210_bus_request(wil, + WIL_11AD_BUS_REQUEST_KBPS); + } vif->bss = bss; /* Connect can take lots of time */ mod_timer(&vif->connect_timer, @@ -2207,8 +2213,13 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, } netif_carrier_on(ndev); - if (!wil_has_other_active_ifaces(wil, ndev, false, true)) - wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); + if (!wil_has_other_active_ifaces(wil, ndev, false, true)) { + if (wil->force_edmg_channel) + wil6210_bus_request(wil, WIL_11AY_BUS_REQUEST_KBPS); + else + wil6210_bus_request(wil, WIL_11AD_BUS_REQUEST_KBPS); + } + rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, wmi_edmg_channel, hidden_ssid, is_go); @@ -2646,6 +2657,10 @@ static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_ps_profile_type ps_profile; + if (wil->vr_profile != WMI_VR_PROFILE_DISABLED) + /* disallow in VR mode */ + return -EINVAL; + wil_dbg_misc(wil, "enabled=%d, timeout=%d\n", enabled, timeout); diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 9ccfe43d8cec..819595071ee1 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -20,6 +20,8 @@ #define WAIT_FOR_SCAN_ABORT_MS 1000 #define WIL_DEFAULT_NUM_RX_STATUS_RINGS 1 #define WIL_BOARD_FILE_MAX_NAMELEN 128 +#define WIL6210_ITR_VR_RX_MAX_BURST_DURATION (5) /* usec */ +#define WIL6210_VR_TX_RING_ORDER 10 bool debug_fw; /* = false; */ module_param(debug_fw, bool, 0444); @@ -104,6 +106,11 @@ MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order"); module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, 0444); MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order"); +static u8 support_sensing_over_spi; +module_param(support_sensing_over_spi, byte, 0444); +MODULE_PARM_DESC(support_sensing_over_spi, + " notify FW to enable SPI for sensing"); + enum { WIL_BOOT_ERR, WIL_BOOT_VANILLA, @@ -1560,6 +1567,38 @@ int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) return rc; } +int wil_vr_update_profile(struct wil6210_priv *wil, u8 profile) +{ + int rc; + + if (profile == WMI_VR_PROFILE_DISABLED) { + /* Switch from VR mode to normal (non-VR) mode is not + * supported at runtime - it requires FW re-loading. + * It is assumed here that FW is not running when VR disable + * is requested + */ + wil->ps_profile = WMI_PS_PROFILE_TYPE_DEFAULT; + tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; + drop_if_ring_full = false; + wil->rx_max_burst_duration = + WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT; + + return 0; + } + + rc = wmi_set_vr_profile(wil, profile); + if (rc) + return rc; + + /* VR default configuration */ + wil->ps_profile = WMI_PS_PROFILE_TYPE_PS_DISABLED; + tx_ring_order = WIL6210_VR_TX_RING_ORDER; + drop_if_ring_full = true; + wil->rx_max_burst_duration = WIL6210_ITR_VR_RX_MAX_BURST_DURATION; + + return 0; +} + static void wil_pre_fw_config(struct wil6210_priv *wil) { wil_clear_fw_log_addr(wil); @@ -1675,6 +1714,15 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil_s(wil, RGF_USER_USAGE_8, BIT_USER_EXT_CLK); } + if (support_sensing_over_spi) { + wil_dbg_misc(wil, "notify FW to enable SPI for sensing\n"); + wil_s(wil, RGF_USER_USAGE_6, BIT_SPI_SENSING_SUPPORT); + wmi_reset_spi_slave(wil); + } else { + wil_dbg_misc(wil, "notify FW to disable SPI for sensing\n"); + wil_c(wil, RGF_USER_USAGE_6, BIT_SPI_SENSING_SUPPORT); + } + if (wil->platform_ops.notify) { rc = wil->platform_ops.notify(wil->platform_handle, WIL_PLATFORM_EVT_PRE_RESET); @@ -1802,6 +1850,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } + /* Update VR mode before configuring interrupt moderation */ + if (wil->vr_profile != WMI_VR_PROFILE_DISABLED) + wil_vr_update_profile(wil, wil->vr_profile); + wil->txrx_ops.configure_interrupt_moderation(wil); /* Enable OFU rdy valid bug fix, to prevent hang in oful34_rx diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 34f5ea8e6520..2f67bd218f58 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -51,6 +51,13 @@ wil_can_suspend_vif(struct wil6210_priv *wil, struct wil6210_vif *vif, /* for STA-like interface, don't runtime suspend */ case NL80211_IFTYPE_STATION: + if (test_bit(wil_vif_fwconnected, vif->status) && + wil->vr_profile != WMI_VR_PROFILE_DISABLED) { + wil_dbg_pm(wil, + "Reject suspend in VR mode when connected\n"); + return false; + } + /* fallthrough */ case NL80211_IFTYPE_P2P_CLIENT: if (test_bit(wil_vif_fwconnecting, vif->status)) { wil_dbg_pm(wil, "Delay suspend when connecting\n"); diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c index f872e8358033..7f3e658f0f76 100644 --- a/drivers/net/wireless/ath/wil6210/sysfs.c +++ b/drivers/net/wireless/ath/wil6210/sysfs.c @@ -297,6 +297,59 @@ out: static DEVICE_ATTR_RW(fst_link_loss); +static ssize_t +vr_profile_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + ssize_t len; + + len = snprintf(buf, PAGE_SIZE, "%s\n", + wil_get_vr_profile_name(wil->vr_profile)); + + return len; +} + +static ssize_t +vr_profile_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wil6210_priv *wil = dev_get_drvdata(dev); + u8 profile; + int rc = 0; + + if (kstrtou8(buf, 0, &profile)) + return -EINVAL; + + if (test_bit(wil_status_fwready, wil->status)) { + wil_err(wil, "Cannot set VR while interface is up\n"); + return -EIO; + } + + if (profile == wil->vr_profile) { + wil_info(wil, "Ignore same VR profile %s\n", + wil_get_vr_profile_name(wil->vr_profile)); + return count; + } + + wil_info(wil, "Sysfs: set VR profile to %s\n", + wil_get_vr_profile_name(profile)); + + /* Enabling of VR mode is done from wil_reset after FW is ready. + * Disabling is done from here. + */ + if (profile == WMI_VR_PROFILE_DISABLED) { + rc = wil_vr_update_profile(wil, profile); + if (rc) + return rc; + } + wil->vr_profile = profile; + + return count; +} + +static DEVICE_ATTR_RW(vr_profile); + static ssize_t snr_thresh_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -339,6 +392,7 @@ static struct attribute *wil6210_sysfs_entries[] = { &dev_attr_thermal_throttling.attr, &dev_attr_fst_link_loss.attr, &dev_attr_snr_thresh.attr, + &dev_attr_vr_profile.attr, NULL }; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index f4022c780302..e5bd9eea2377 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -52,6 +52,8 @@ union wil_tx_desc; #define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ +#define WIL_11AD_BUS_REQUEST_KBPS 600000 /* ~4.6Gbps */ +#define WIL_11AY_BUS_REQUEST_KBPS 1300000 /* ~10.1Gbps */ #define WIL_NUM_LATENCY_BINS 200 @@ -181,6 +183,7 @@ struct RGF_ICR { #define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_2 (0x880008) #define RGF_USER_USAGE_6 (0x880018) + #define BIT_SPI_SENSING_SUPPORT BIT(28) #define BIT_USER_OOB_MODE BIT(31) #define BIT_USER_OOB_R2_MODE BIT(30) #define RGF_USER_USAGE_8 (0x880020) @@ -1051,6 +1054,9 @@ struct wil6210_priv { short direct; } snr_thresh; + /* VR profile, VR is disabled on profile 0 */ + u8 vr_profile; + /* current reg domain configured in kernel */ char regdomain[3]; /* alpha2 */ @@ -1254,6 +1260,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac); int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx); void wil_set_ethtoolops(struct net_device *ndev); +int wil_vr_update_profile(struct wil6210_priv *wil, u8 profile); struct fw_map *wil_find_fw_mapping(const char *section); void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size); @@ -1449,6 +1456,10 @@ void wil_halp_unvote(struct wil6210_priv *wil); void wil6210_set_halp(struct wil6210_priv *wil); void wil6210_clear_halp(struct wil6210_priv *wil); +int wmi_set_vr_profile(struct wil6210_priv *wil, u8 profile); +const char * +wil_get_vr_profile_name(enum wmi_vr_profile profile); + void wil_ftm_init(struct wil6210_vif *vif); void wil_ftm_deinit(struct wil6210_vif *vif); void wil_ftm_stop_operations(struct wil6210_priv *wil); @@ -1502,6 +1513,7 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u16 agg_wsize, u16 timeout); void update_supported_bands(struct wil6210_priv *wil); +int wmi_reset_spi_slave(struct wil6210_priv *wil); void wil_clear_fw_log_addr(struct wil6210_priv *wil); #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c72024d61e06..16aea74398e1 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -32,6 +32,7 @@ MODULE_PARM_DESC(led_id, #define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200 #define WIL_WMI_PCP_STOP_TO_MS 5000 +#define WIL_WMI_SPI_SLAVE_RESET_TO_MS 500 /** * WMI event receiving - theory of operations @@ -478,6 +479,10 @@ static const char *cmdid2name(u16 cmdid) return "WMI_RBUFCAP_CFG_CMD"; case WMI_TEMP_SENSE_ALL_CMDID: return "WMI_TEMP_SENSE_ALL_CMDID"; + case WMI_SET_VR_PROFILE_CMDID: + return "WMI_SET_VR_PROFILE_CMD"; + case WMI_RESET_SPI_SLAVE_CMDID: + return "WMI_RESET_SPI_SLAVE_CMD"; default: return "Untracked CMD"; } @@ -626,6 +631,10 @@ static const char *eventid2name(u16 eventid) return "WMI_RBUFCAP_CFG_EVENT"; case WMI_TEMP_SENSE_ALL_DONE_EVENTID: return "WMI_TEMP_SENSE_ALL_DONE_EVENTID"; + case WMI_SET_VR_PROFILE_EVENTID: + return "WMI_SET_VR_PROFILE_EVENT"; + case WMI_RESET_SPI_SLAVE_EVENTID: + return "WMI_RESET_SPI_SLAVE_EVENT"; default: return "Untracked EVENT"; } @@ -2070,8 +2079,9 @@ void wmi_recv_cmd(struct wil6210_priv *wil) n - num_immed_reply, num_immed_reply); } -int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len, - u16 reply_id, void *reply, u16 reply_size, int to_msec) +static int __wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, + u16 len, u16 reply_id, void *reply, u16 reply_size, + int to_msec, bool force_send) { int rc; unsigned long remain; @@ -2087,7 +2097,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len, reinit_completion(&wil->wmi_call); spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); - rc = __wmi_send(wil, cmdid, mid, buf, len, false); + rc = __wmi_send(wil, cmdid, mid, buf, len, force_send); if (rc) goto out; @@ -2117,6 +2127,13 @@ out: return rc; } +int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len, + u16 reply_id, void *reply, u16 reply_size, int to_msec) +{ + return __wmi_call(wil, cmdid, mid, buf, len, reply_id, reply, + reply_size, to_msec, false); +} + int wmi_echo(struct wil6210_priv *wil) { struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); @@ -4211,3 +4228,84 @@ int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval) return 0; } + +const char * +wil_get_vr_profile_name(enum wmi_vr_profile profile) +{ + switch (profile) { + case WMI_VR_PROFILE_DISABLED: + return "DISABLED"; + case WMI_VR_PROFILE_COMMON_AP: + return "COMMON_AP"; + case WMI_VR_PROFILE_COMMON_STA: + return "COMMON_STA"; + default: + return "unknown"; + } +} + +int wmi_set_vr_profile(struct wil6210_priv *wil, u8 profile) +{ + int rc; + struct net_device *ndev = wil->main_ndev; + struct wil6210_vif *vif = ndev_to_vif(ndev); + struct wmi_set_vr_profile_cmd cmd = {0}; + struct { + struct wmi_cmd_hdr hdr; + struct wmi_set_vr_profile_event evt; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + + cmd.profile = profile; + wil_info(wil, "sending set vr config command, profile=%d\n", profile); + rc = wmi_call(wil, WMI_SET_VR_PROFILE_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_SET_VR_PROFILE_EVENTID, + &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "WMI_SET_VR_PROFILE_CMDID failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "set vr profile failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + return 0; +} + +int wmi_reset_spi_slave(struct wil6210_priv *wil) +{ + struct net_device *ndev = wil->main_ndev; + struct wil6210_vif *vif = ndev_to_vif(ndev); + struct wmi_reset_spi_slave_cmd cmd = { {0} }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_reset_spi_slave_event evt; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + int rc; + + if (!(ndev->flags & IFF_UP)) + return 0; + + /* Force sending SPI slave reset to guarantee safe SPI reset */ + rc = __wmi_call(wil, WMI_RESET_SPI_SLAVE_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_RESET_SPI_SLAVE_EVENTID, &reply, + sizeof(reply), WIL_WMI_SPI_SLAVE_RESET_TO_MS, true); + if (rc) { + wil_err(wil, "WMI_RESET_SPI_SLAVE_CMDID failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "spi slave reset failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 87138708f32b..c2d4eac96fb3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -140,6 +140,7 @@ enum wmi_command_id { WMI_RADAR_SET_MODE_CMDID = 0x103, WMI_RADAR_CONTROL_CMDID = 0x104, WMI_RADAR_PCI_CONTROL_CMDID = 0x105, + WMI_RESET_SPI_SLAVE_CMDID = 0x106, WMI_MEM_READ_CMDID = 0x800, WMI_MEM_WR_CMDID = 0x801, WMI_ECHO_CMDID = 0x803, @@ -284,6 +285,7 @@ enum wmi_command_id { WMI_GET_ASSOC_LIST_CMDID = 0xA06, WMI_GET_CCA_INDICATIONS_CMDID = 0xA07, WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_CMDID = 0xA08, + WMI_SET_VR_PROFILE_CMDID = 0xA09, WMI_INTERNAL_FW_IOCTL_CMDID = 0xA0B, WMI_LINK_STATS_CMDID = 0xA0C, WMI_SET_GRANT_MCS_CMDID = 0xA0E, @@ -692,6 +694,11 @@ struct wmi_radar_pci_control_cmd { __le32 reserved; } __packed; +/* WMI_RESET_SPI_SLAVE_CMDID */ +struct wmi_reset_spi_slave_cmd { + u8 reserved[4]; +} __packed; + /* WMI_RF_MGMT_CMDID */ enum wmi_rf_mgmt_type { WMI_RF_MGMT_W_DISABLE = 0x00, @@ -1734,6 +1741,13 @@ struct wmi_radar_pci_control_event { u8 reserved[3]; } __packed; +/* WMI_RESET_SPI_SLAVE_EVENTID */ +struct wmi_reset_spi_slave_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_SET_LONG_RANGE_CONFIG_CMDID */ struct wmi_set_long_range_config_cmd { __le32 reserved; @@ -1980,6 +1994,7 @@ enum wmi_event_id { WMI_RADAR_SET_MODE_EVENTID = 0x1103, WMI_RADAR_CONTROL_EVENTID = 0x1104, WMI_RADAR_PCI_CONTROL_EVENTID = 0x1105, + WMI_RESET_SPI_SLAVE_EVENTID = 0x1106, WMI_RD_MEM_RSP_EVENTID = 0x1800, WMI_FW_READY_EVENTID = 0x1801, WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200, @@ -2110,6 +2125,7 @@ enum wmi_event_id { WMI_GET_ASSOC_LIST_RES_EVENTID = 0x1A06, WMI_GET_CCA_INDICATIONS_EVENTID = 0x1A07, WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_EVENTID = 0x1A08, + WMI_SET_VR_PROFILE_EVENTID = 0x1A09, WMI_INTERNAL_FW_EVENT_EVENTID = 0x1A0A, WMI_INTERNAL_FW_IOCTL_EVENTID = 0x1A0B, WMI_LINK_STATS_CONFIG_DONE_EVENTID = 0x1A0C, @@ -4158,6 +4174,32 @@ struct wmi_rbufcap_cfg_cmd { __le16 rx_desc_threshold; } __packed; +enum wmi_vr_profile { + WMI_VR_PROFILE_DISABLED = 0, + WMI_VR_PROFILE_COMMON_AP = 1, + WMI_VR_PROFILE_COMMON_STA = 2, + WMI_VR_PROFILE_RESERVED0 = 250, + WMI_VR_PROFILE_RESERVED1 = 251, + WMI_VR_PROFILE_RESERVED2 = 252, + WMI_VR_PROFILE_RESERVED3 = 253, + WMI_VR_PROFILE_RESERVED4 = 254, + WMI_VR_PROFILE_RESERVED5 = 255, +}; + +/* WMI_SET_VR_PROFILE_CMDID */ +struct wmi_set_vr_profile_cmd { + /* enum wmi_vr_profile */ + u8 profile; + u8 reserved[3]; +} __packed; + +/* WMI_SET_VR_PROFILE_EVENTID */ +struct wmi_set_vr_profile_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_RBUFCAP_CFG_EVENTID */ struct wmi_rbufcap_cfg_event { /* enum wmi_fw_status */