// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of wl1271 * * Copyright (C) 2009 Nokia Corporation * * Contact: Luciano Coelho <luciano.coelho@nokia.com>
*/
/* * add the station to the known list before transmitting the * authentication response. this way it won't get de-authed by FW * when transmitting too soon.
*/
wl1271_acx_set_inconnection_sta(wl, wlvif, hdr->addr1);
/* * ROC for 1 second on the AP channel for completing the connection. * Note the ROC will be continued by the update_sta_state callbacks * once the station reaches the associated state.
*/
wlcore_update_inconn_sta(wl, wlvif, NULL, true);
wlvif->pending_auth_reply_time = jiffies;
cancel_delayed_work(&wlvif->pending_auth_complete_work);
ieee80211_queue_delayed_work(wl->hw,
&wlvif->pending_auth_complete_work,
msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT));
}
/* * if in FW PS and there is enough data in FW we can put the link * into high-level PS and clean out its TX queues. * Make an exception if this is the only connected link. In this * case FW-memory congestion is less of a problem. * Note that a single connected STA means 2*ap_count + 1 active links, * since we must account for the global and broadcast AP links * for each AP. The "fw_ps" check assures us the other link is a STA * connected to the AP. Otherwise the FW would not set the PSM bit.
*/ if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps &&
tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
/* * If the FW was empty before, arm the Tx watchdog. Also do * this on the first Tx after resume, as we always cancel the * watchdog on suspend.
*/ if (wl->tx_allocated_blocks == total_blocks ||
test_and_clear_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags))
wl12xx_rearm_tx_watchdog_locked(wl);
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
wl->tx_allocated_pkts[ac]++;
if (test_bit(hlid, wl->links_map))
wl->links[hlid].allocated_pkts++;
/* queue */
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
desc->tid = skb->priority;
if (is_dummy) { /* * FW expects the dummy packet to have an invalid session id - * any session id that is different than the one set in the join
*/
tx_attr = (SESSION_COUNTER_INVALID <<
TX_HW_ATTR_OFST_SESSION_COUNTER) &
TX_HW_ATTR_SESSION_COUNTER;
/* for WEP shared auth - no fw encryption is needed */ if (ieee80211_is_auth(frame_control) &&
ieee80211_has_protected(frame_control))
tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
/* send EAPOL frames as voice */ if (control->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)
tx_attr |= TX_HW_ATTR_EAPOL_FRAME;
/* * The length of each packet is stored in terms of * words. Thus, we must pad the skb data to make sure its * length is aligned. The number of padding bytes is computed * and set in wl1271_tx_fill_hdr. * In special cases, we want to align to a specific block size * (eg. for wl128x with SDIO we align to 256).
*/
total_len = wlcore_calc_packet_alignment(wl, skb->len);
band = wl->hw->wiphy->bands[rate_band]; for (bit = 0; bit < band->n_bitrates; bit++) { if (rate_set & 0x1)
enabled_rates |= band->bitrates[bit].hw_value;
rate_set >>= 1;
}
/* MCS rates indication are on bits 16 - 31 */
rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
for (bit = 0; bit < 16; bit++) { if (rate_set & 0x1)
enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
rate_set >>= 1;
}
return enabled_rates;
}
void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
{ int i; struct wl12xx_vif *wlvif;
wl12xx_for_each_wlvif(wl, wlvif) { for (i = 0; i < NUM_TX_QUEUES; i++) { if (wlcore_is_queue_stopped_by_reason(wl, wlvif, i,
WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
wlvif->tx_queue_count[i] <=
WL1271_TX_QUEUE_LOW_WATERMARK) /* firmware buffer has space, restart queues */
wlcore_wake_queue(wl, wlvif, i,
WLCORE_QUEUE_STOP_REASON_WATERMARK);
}
}
}
staticint wlcore_select_ac(struct wl1271 *wl)
{ int i, q = -1, ac;
u32 min_pkts = 0xffffffff;
/* * Find a non-empty ac where: * 1. There are packets to transmit * 2. The FW has the least allocated blocks * * We prioritize the ACs according to VO>VI>BE>BK
*/ for (i = 0; i < NUM_TX_QUEUES; i++) {
ac = wl1271_tx_get_queue(i); if (wl->tx_queue_count[ac] &&
wl->tx_allocated_pkts[ac] < min_pkts) {
q = ac;
min_pkts = wl->tx_allocated_pkts[q];
}
}
if (!wlcore_hw_lnk_high_prio(wl, hlid, lnk)) { if (*low_prio_hlid == WL12XX_INVALID_LINK_ID &&
!skb_queue_empty(&lnk->tx_queue[ac]) &&
wlcore_hw_lnk_low_prio(wl, hlid, lnk)) /* we found the first non-empty low priority queue */
*low_prio_hlid = hlid;
/* continue from last wlvif (round robin) */ if (wlvif) {
wl12xx_for_each_wlvif_continue(wl, wlvif) { if (!wlvif->tx_queue_count[ac]) continue;
skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid,
&low_prio_hlid); if (!skb) continue;
wl->last_wlvif = wlvif; break;
}
}
/* dequeue from the system HLID before the restarting wlvif list */ if (!skb) {
skb = wlcore_lnk_dequeue_high_prio(wl, wl->system_hlid,
ac, &low_prio_hlid); if (skb) {
*hlid = wl->system_hlid;
wl->last_wlvif = NULL;
}
}
/* Do a new pass over the wlvif list. But no need to continue
* after last_wlvif. The previous pass should have found it. */ if (!skb) {
wl12xx_for_each_wlvif(wl, wlvif) { if (!wlvif->tx_queue_count[ac]) goto next;
/* * Returns failure values only in case of failed bus ops within this function. * wl1271_prepare_tx_frame retvals won't be returned in order to avoid * triggering recovery by higher layers when not necessary. * In case a FW command fails within wl1271_prepare_tx_frame fails a recovery * will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame * can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING * within prepare_tx_frame code but there's nothing we should do about those * as well.
*/ int wlcore_tx_work_locked(struct wl1271 *wl)
{ struct wl12xx_vif *wlvif; struct sk_buff *skb; struct wl1271_tx_hw_descr *desc;
u32 buf_offset = 0, last_len = 0; bool sent_packets = false; unsignedlong active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0}; int ret = 0; int bus_ret = 0;
u8 hlid;
if (unlikely(wl->state != WLCORE_STATE_ON)) return 0;
sent_packets = true;
} if (sent_packets) { /* * Interrupt the firmware with the new packets. This is only * required for older hardware revisions
*/ if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS,
wl->tx_packets_count); if (bus_ret < 0) goto out;
}
/* * TODO: use wl12xx constants when this code is moved to wl12xx, as * only it uses Tx-completion.
*/ if (rate_class_index <= 8)
flags |= IEEE80211_TX_RC_MCS;
/* * TODO: use wl12xx constants when this code is moved to wl12xx, as * only it uses Tx-completion.
*/ if (rate_class_index == 0)
flags |= IEEE80211_TX_RC_SHORT_GI;
/* remove private header from packet */
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
/* remove TKIP header space if present */ if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
info->control.hw_key &&
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
hdrlen);
skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
}
wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" " status 0x%x",
result->id, skb, result->ack_failures,
result->rate_class_index, result->status);
/* return the packet to the stack */
skb_queue_tail(&wl->deferred_tx_queue, skb);
queue_work(wl->freezable_wq, &wl->netstack_work);
wl1271_free_tx_id(wl, result->id);
}
/* Called upon reception of a TX complete interrupt */ int wlcore_tx_complete(struct wl1271 *wl)
{ struct wl1271_acx_mem_map *memmap = wl->target_mem_map;
u32 count, fw_counter;
u32 i; int ret;
/* read the tx results from the chipset */
ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result),
wl->tx_res_if, sizeof(*wl->tx_res_if), false); if (ret < 0) goto out;
/* verify that the result buffer is not getting overrun */ if (unlikely(count > TX_HW_RESULT_QUEUE_LEN))
wl1271_warning("TX result overflow from chipset: %d", count);
/* process the results */ for (i = 0; i < count; i++) { struct wl1271_tx_hw_res_descr *result;
u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK;
/* process the packet */
result = &(wl->tx_res_if->tx_results_queue[offset]);
wl1271_tx_complete_packet(wl, result);
for (i = 0; i < NUM_TX_QUEUES; i++)
wlvif->tx_queue_count[i] = 0;
} /* caller must hold wl->mutex and TX must be stopped */ void wl12xx_tx_reset(struct wl1271 *wl)
{ int i; struct sk_buff *skb; struct ieee80211_tx_info *info;
/* only reset the queues if something bad happened */ if (wl1271_tx_total_queue_count(wl) != 0) { for (i = 0; i < wl->num_links; i++)
wl1271_tx_reset_link_queues(wl, i);
for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_queue_count[i] = 0;
}
/* * Make sure the driver is at a consistent state, in case this * function is called from a context other than interface removal. * This call will always wake the TX queues.
*/
wl1271_handle_tx_low_watermark(wl);
for (i = 0; i < wl->num_tx_desc; i++) { if (wl->tx_frames[i] == NULL) continue;
/* force Tx and give the driver some time to flush data */
mutex_unlock(&wl->mutex); if (wl1271_tx_total_queue_count(wl))
wl1271_tx_work(&wl->tx_work);
msleep(20);
mutex_lock(&wl->mutex);
/* mark all possible queues as stopped */ for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++)
WARN_ON_ONCE(test_and_set_bit(reason,
&wl->queue_stop_reasons[i]));
/* use the global version to make sure all vifs in mac80211 we don't * know are stopped.
*/
ieee80211_stop_queues(wl->hw);
/* mark all possible queues as awake */ for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++)
WARN_ON_ONCE(!test_and_clear_bit(reason,
&wl->queue_stop_reasons[i]));
/* use the global version to make sure all vifs in mac80211 we don't * know are woken up.
*/
ieee80211_wake_queues(wl->hw);
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.