|
@@ -848,17 +848,12 @@ static void wl18xx_tx_immediate_completion(struct wl1271 *wl)
|
|
|
wl18xx_tx_immediate_complete(wl);
|
|
|
}
|
|
|
|
|
|
-static int wl18xx_hw_init(struct wl1271 *wl)
|
|
|
+static int wl18xx_set_host_cfg_bitmap(struct wl1271 *wl, u32 extra_mem_blk)
|
|
|
{
|
|
|
int ret;
|
|
|
- struct wl18xx_priv *priv = wl->priv;
|
|
|
- u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE |
|
|
|
- HOST_IF_CFG_ADD_RX_ALIGNMENT;
|
|
|
-
|
|
|
u32 sdio_align_size = 0;
|
|
|
-
|
|
|
- /* (re)init private structures. Relevant on recovery as well. */
|
|
|
- priv->last_fw_rls_idx = 0;
|
|
|
+ u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE |
|
|
|
+ HOST_IF_CFG_ADD_RX_ALIGNMENT;
|
|
|
|
|
|
/* Enable Tx SDIO padding */
|
|
|
if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) {
|
|
@@ -873,12 +868,28 @@ static int wl18xx_hw_init(struct wl1271 *wl)
|
|
|
}
|
|
|
|
|
|
ret = wl18xx_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap,
|
|
|
- sdio_align_size,
|
|
|
- WL18XX_TX_HW_EXTRA_BLOCK_SPARE,
|
|
|
+ sdio_align_size, extra_mem_blk,
|
|
|
WL18XX_HOST_IF_LEN_SIZE_FIELD);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int wl18xx_hw_init(struct wl1271 *wl)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ struct wl18xx_priv *priv = wl->priv;
|
|
|
+
|
|
|
+ /* (re)init private structures. Relevant on recovery as well. */
|
|
|
+ priv->last_fw_rls_idx = 0;
|
|
|
+ priv->extra_spare_vif_count = 0;
|
|
|
+
|
|
|
+ /* set the default amount of spare blocks in the bitmap */
|
|
|
+ ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
if (checksum_param) {
|
|
|
ret = wl18xx_acx_set_checksum_state(wl);
|
|
|
if (ret != 0)
|
|
@@ -1036,8 +1047,68 @@ static int wl18xx_handle_static_data(struct wl1271 *wl,
|
|
|
|
|
|
static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
|
|
|
{
|
|
|
- /* TODO: dynamically change to extra only when we have GEM or TKIP */
|
|
|
- return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
|
|
|
+ struct wl18xx_priv *priv = wl->priv;
|
|
|
+
|
|
|
+ /* If we have VIFs requiring extra spare, indulge them */
|
|
|
+ if (priv->extra_spare_vif_count)
|
|
|
+ return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
|
|
|
+
|
|
|
+ return WL18XX_TX_HW_BLOCK_SPARE;
|
|
|
+}
|
|
|
+
|
|
|
+static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
+ struct ieee80211_key_conf *key_conf)
|
|
|
+{
|
|
|
+ struct wl18xx_priv *priv = wl->priv;
|
|
|
+ bool change_spare = false;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * when adding the first or removing the last GEM/TKIP interface,
|
|
|
+ * we have to adjust the number of spare blocks.
|
|
|
+ */
|
|
|
+ change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
|
|
|
+ key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) &&
|
|
|
+ ((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) ||
|
|
|
+ (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY));
|
|
|
+
|
|
|
+ /* no need to change spare - just regular set_key */
|
|
|
+ if (!change_spare)
|
|
|
+ return wlcore_set_key(wl, cmd, vif, sta, key_conf);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * stop the queues and flush to ensure the next packets are
|
|
|
+ * in sync with FW spare block accounting
|
|
|
+ */
|
|
|
+ wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
|
|
|
+ wl1271_tx_flush(wl);
|
|
|
+
|
|
|
+ ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* key is now set, change the spare blocks */
|
|
|
+ if (cmd == SET_KEY) {
|
|
|
+ ret = wl18xx_set_host_cfg_bitmap(wl,
|
|
|
+ WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ priv->extra_spare_vif_count++;
|
|
|
+ } else {
|
|
|
+ ret = wl18xx_set_host_cfg_bitmap(wl,
|
|
|
+ WL18XX_TX_HW_BLOCK_SPARE);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ priv->extra_spare_vif_count--;
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static struct wlcore_ops wl18xx_ops = {
|
|
@@ -1063,6 +1134,7 @@ static struct wlcore_ops wl18xx_ops = {
|
|
|
.debugfs_init = wl18xx_debugfs_add_files,
|
|
|
.handle_static_data = wl18xx_handle_static_data,
|
|
|
.get_spare_blocks = wl18xx_get_spare_blocks,
|
|
|
+ .set_key = wl18xx_set_key,
|
|
|
};
|
|
|
|
|
|
/* HT cap appropriate for wide channels */
|