diff options
Diffstat (limited to 'drivers/staging/wfx')
33 files changed, 2347 insertions, 3060 deletions
diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile index 0d9c1ed092f6..0e0cc982ceab 100644 --- a/drivers/staging/wfx/Makefile +++ b/drivers/staging/wfx/Makefile @@ -7,6 +7,7 @@ wfx-y := \ bh.o \ hwio.o \ fwio.o \ + hif_tx_mib.o \ hif_tx.o \ hif_rx.o \ queue.o \ diff --git a/drivers/staging/wfx/TODO b/drivers/staging/wfx/TODO index efcb7c6a5aa7..42bf36d43970 100644 --- a/drivers/staging/wfx/TODO +++ b/drivers/staging/wfx/TODO @@ -1,60 +1,25 @@ This is a list of things that need to be done to get this driver out of the staging directory. - - All structures defined in hif_api_*.h are intended to sent/received to/from - hardware. All their members whould be declared __le32 or __le16. - See: - https://lore.kernel.org/lkml/20191111202852.GX26530@ZenIV.linux.org.uk + - The HIF API is not yet clean enough. - - Once previous item done, it will be possible to audit the driver with - `sparse'. It will probably find tons of problems with big endian - architectures. - - - hif_api_*.h whave been imported from firmware code. Some of the structures - are never used in driver. - - - Driver try to maintains power save status of the stations. However, this - work is already done by mac80211. sta_asleep_mask and pspoll_mask should be - dropped. - - - wfx_tx_queues_get() should be reworked. It currently try compute itself the - QoS policy. However, firmware already do the job. Firmware would prefer to - have a few packets in each queue and be able to choose itself which queue to - use. + - The code that check the corectness of received message (in rx_helper()) can + be improved. See: + https://lore.kernel.org/driverdev-devel/2302785.6C7ODC2LYm@pc-42/ - As suggested by Felix, rate control could be improved following this idea: https://lore.kernel.org/lkml/3099559.gv3Q75KnN1@pc-42/ - - When driver is about to loose BSS, it forge its own Null Func request (see - wfx_cqm_bssloss_sm()). It should use mechanism provided by mac80211. - - - AP is actually is setup after a call to wfx_bss_info_changed(). Yet, - ieee80211_ops provide callback start_ap(). - - - The current process for joining a network is incredibly complex. Should be - reworked. - - - Monitoring mode is not implemented despite being mandatory by mac80211. - - - "compatible" value are not correct. They should be "vendor,chip". See: - https://lore.kernel.org/driverdev-devel/5226570.CMH5hVlZcI@pc-42 - - - The "state" field from wfx_vif should be replaced by "vif->type". - - - It seems that wfx_upload_keys() is useless. - - - "event_queue" from wfx_vif seems overkill. These event are rare and they - probably could be handled in a simpler fashion. - - Feature called "secure link" should be either developed (using kernel crypto API) or dropped. + - The device allows to filter multicast traffic. The code to support these + filters exists in the driver but it is disabled because it has never been + tested. + - In wfx_cmd_send(), "async" allow to send command without waiting the reply. It may help in some situation, but it is not yet used. In add, it may cause some trouble: https://lore.kernel.org/driverdev-devel/alpine.DEB.2.21.1910041317381.2992@hadrien/ So, fix it (by replacing the mutex with a semaphore) or drop it. - - Chip support P2P, but driver does not implement it. - - - Chip support kind of Mesh, but driver does not implement it. diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c index 9fcab00a3733..1cbaf8bb4fa3 100644 --- a/drivers/staging/wfx/bh.c +++ b/drivers/staging/wfx/bh.c @@ -70,7 +70,7 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) if (wfx_data_read(wdev, skb->data, alloc_len)) goto err; - piggyback = le16_to_cpup((u16 *)(skb->data + alloc_len - 2)); + piggyback = le16_to_cpup((__le16 *)(skb->data + alloc_len - 2)); _trace_piggyback(piggyback, false); hif = (struct hif_msg *)skb->data; @@ -84,13 +84,12 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) // piggyback is probably correct. return piggyback; } - le16_to_cpus(&hif->len); - computed_len = round_up(hif->len - sizeof(hif->len), 16) - + sizeof(struct hif_sl_msg) - + sizeof(struct hif_sl_tag); + computed_len = + round_up(le16_to_cpu(hif->len) - sizeof(hif->len), 16) + + sizeof(struct hif_sl_msg) + + sizeof(struct hif_sl_tag); } else { - le16_to_cpus(&hif->len); - computed_len = round_up(hif->len, 2); + computed_len = round_up(le16_to_cpu(hif->len), 2); } if (computed_len != read_len) { dev_err(wdev->dev, "inconsistent message length: %zu != %zu\n", @@ -103,13 +102,11 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) if (!(hif->id & HIF_ID_IS_INDICATION)) { (*is_cnf)++; if (hif->id == HIF_CNF_ID_MULTI_TRANSMIT) - release_count = le32_to_cpu(((struct hif_cnf_multi_transmit *)hif->body)->num_tx_confs); + release_count = ((struct hif_cnf_multi_transmit *)hif->body)->num_tx_confs; else release_count = 1; WARN(wdev->hif.tx_buffers_used < release_count, "corrupted buffer counter"); wdev->hif.tx_buffers_used -= release_count; - if (!wdev->hif.tx_buffers_used) - wake_up(&wdev->hif.tx_buffers_empty); } _trace_hif_recv(hif, wdev->hif.tx_buffers_used); @@ -120,9 +117,11 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) wdev->hif.rx_seqnum = (hif->seqnum + 1) % (HIF_COUNTER_MAX + 1); } - skb_put(skb, hif->len); + skb_put(skb, le16_to_cpu(hif->len)); // wfx_handle_rx takes care on SKB livetime wfx_handle_rx(wdev, skb); + if (!wdev->hif.tx_buffers_used) + wake_up(&wdev->hif.tx_buffers_empty); return piggyback; @@ -307,6 +306,35 @@ void wfx_bh_request_tx(struct wfx_dev *wdev) queue_work(system_highpri_wq, &wdev->hif.bh); } +/* + * If IRQ is not available, this function allow to manually poll the control + * register and simulate an IRQ ahen an event happened. + * + * Note that the device has a bug: If an IRQ raise while host read control + * register, the IRQ is lost. So, use this function carefully (only duing + * device initialisation). + */ +void wfx_bh_poll_irq(struct wfx_dev *wdev) +{ + ktime_t now, start; + u32 reg; + + WARN(!wdev->poll_irq, "unexpected IRQ polling can mask IRQ"); + start = ktime_get(); + for (;;) { + control_reg_read(wdev, ®); + now = ktime_get(); + if (reg & 0xFFF) + break; + if (ktime_after(now, ktime_add_ms(start, 1000))) { + dev_err(wdev->dev, "time out while polling control register\n"); + return; + } + udelay(200); + } + wfx_bh_request_rx(wdev); +} + void wfx_bh_register(struct wfx_dev *wdev) { INIT_WORK(&wdev->hif.bh, bh_work); diff --git a/drivers/staging/wfx/bh.h b/drivers/staging/wfx/bh.h index 93ca98424e0b..4b73437869e1 100644 --- a/drivers/staging/wfx/bh.h +++ b/drivers/staging/wfx/bh.h @@ -28,5 +28,6 @@ void wfx_bh_register(struct wfx_dev *wdev); void wfx_bh_unregister(struct wfx_dev *wdev); void wfx_bh_request_rx(struct wfx_dev *wdev); void wfx_bh_request_tx(struct wfx_dev *wdev); +void wfx_bh_poll_irq(struct wfx_dev *wdev); #endif /* WFX_BH_H */ diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h index 62d6ecabe4cb..0370b6c59863 100644 --- a/drivers/staging/wfx/bus.h +++ b/drivers/staging/wfx/bus.h @@ -25,6 +25,8 @@ struct hwbus_ops { void *dst, size_t count); int (*copy_to_io)(void *bus_priv, unsigned int addr, const void *src, size_t count); + int (*irq_subscribe)(void *bus_priv); + int (*irq_unsubscribe)(void *bus_priv); void (*lock)(void *bus_priv); void (*unlock)(void *bus_priv); size_t (*align_size)(void *bus_priv, size_t size); diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c index dedc3ff58d3e..496bfc8bbacc 100644 --- a/drivers/staging/wfx/bus_sdio.c +++ b/drivers/staging/wfx/bus_sdio.c @@ -6,10 +6,12 @@ * Copyright (c) 2010, ST-Ericsson */ #include <linux/module.h> +#include <linux/mmc/sdio.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/card.h> #include <linux/interrupt.h> #include <linux/of_irq.h> +#include <linux/irq.h> #include "bus.h" #include "wfx.h" @@ -91,53 +93,58 @@ static void wfx_sdio_irq_handler(struct sdio_func *func) { struct wfx_sdio_priv *bus = sdio_get_drvdata(func); - if (bus->core) - wfx_bh_request_rx(bus->core); - else - WARN(!bus->core, "race condition in driver init/deinit"); + wfx_bh_request_rx(bus->core); } static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv) { struct wfx_sdio_priv *bus = priv; - if (!bus->core) { - WARN(!bus->core, "race condition in driver init/deinit"); - return IRQ_NONE; - } sdio_claim_host(bus->func); wfx_bh_request_rx(bus->core); sdio_release_host(bus->func); return IRQ_HANDLED; } -static int wfx_sdio_irq_subscribe(struct wfx_sdio_priv *bus) +static int wfx_sdio_irq_subscribe(void *priv) { + struct wfx_sdio_priv *bus = priv; + u32 flags; int ret; + u8 cccr; - if (bus->of_irq) { - ret = request_irq(bus->of_irq, wfx_sdio_irq_handler_ext, - IRQF_TRIGGER_RISING, "wfx", bus); - } else { + if (!bus->of_irq) { sdio_claim_host(bus->func); ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler); sdio_release_host(bus->func); + return ret; } - return ret; + + sdio_claim_host(bus->func); + cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL); + cccr |= BIT(0); + cccr |= BIT(bus->func->num); + sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL); + sdio_release_host(bus->func); + flags = irq_get_trigger_type(bus->of_irq); + if (!flags) + flags = IRQF_TRIGGER_HIGH; + flags |= IRQF_ONESHOT; + return devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL, + wfx_sdio_irq_handler_ext, flags, + "wfx", bus); } -static int wfx_sdio_irq_unsubscribe(struct wfx_sdio_priv *bus) +static int wfx_sdio_irq_unsubscribe(void *priv) { + struct wfx_sdio_priv *bus = priv; int ret; - if (bus->of_irq) { - free_irq(bus->of_irq, bus); - ret = 0; - } else { - sdio_claim_host(bus->func); - ret = sdio_release_irq(bus->func); - sdio_release_host(bus->func); - } + if (bus->of_irq) + devm_free_irq(&bus->func->dev, bus->of_irq, bus); + sdio_claim_host(bus->func); + ret = sdio_release_irq(bus->func); + sdio_release_host(bus->func); return ret; } @@ -151,12 +158,20 @@ static size_t wfx_sdio_align_size(void *priv, size_t size) static const struct hwbus_ops wfx_sdio_hwbus_ops = { .copy_from_io = wfx_sdio_copy_from_io, .copy_to_io = wfx_sdio_copy_to_io, + .irq_subscribe = wfx_sdio_irq_subscribe, + .irq_unsubscribe = wfx_sdio_irq_unsubscribe, .lock = wfx_sdio_lock, .unlock = wfx_sdio_unlock, .align_size = wfx_sdio_align_size, }; -static const struct of_device_id wfx_sdio_of_match[]; +static const struct of_device_id wfx_sdio_of_match[] = { + { .compatible = "silabs,wfx-sdio" }, + { .compatible = "silabs,wf200" }, + { }, +}; +MODULE_DEVICE_TABLE(of, wfx_sdio_of_match); + static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { @@ -165,7 +180,8 @@ static int wfx_sdio_probe(struct sdio_func *func, int ret; if (func->num != 1) { - dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n", func->num); + dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n", + func->num); return -ENODEV; } @@ -207,18 +223,12 @@ static int wfx_sdio_probe(struct sdio_func *func, goto err1; } - ret = wfx_sdio_irq_subscribe(bus); - if (ret) - goto err1; - ret = wfx_probe(bus->core); if (ret) - goto err2; + goto err1; return 0; -err2: - wfx_sdio_irq_unsubscribe(bus); err1: sdio_claim_host(func); sdio_disable_func(func); @@ -232,7 +242,6 @@ static void wfx_sdio_remove(struct sdio_func *func) struct wfx_sdio_priv *bus = sdio_get_drvdata(func); wfx_release(bus->core); - wfx_sdio_irq_unsubscribe(bus); sdio_claim_host(func); sdio_disable_func(func); sdio_release_host(func); @@ -248,15 +257,6 @@ static const struct sdio_device_id wfx_sdio_ids[] = { }; MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids); -#ifdef CONFIG_OF -static const struct of_device_id wfx_sdio_of_match[] = { - { .compatible = "silabs,wfx-sdio" }, - { .compatible = "silabs,wf200" }, - { }, -}; -MODULE_DEVICE_TABLE(of, wfx_sdio_of_match); -#endif - struct sdio_driver wfx_sdio_driver = { .name = "wfx-sdio", .id_table = wfx_sdio_ids, @@ -264,6 +264,6 @@ struct sdio_driver wfx_sdio_driver = { .remove = wfx_sdio_remove, .drv = { .owner = THIS_MODULE, - .of_match_table = of_match_ptr(wfx_sdio_of_match), + .of_match_table = wfx_sdio_of_match, } }; diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c index 61e99b09decb..e8da61fb096b 100644 --- a/drivers/staging/wfx/bus_spi.c +++ b/drivers/staging/wfx/bus_spi.c @@ -12,6 +12,7 @@ #include <linux/gpio/consumer.h> #include <linux/spi/spi.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/of.h> #include "bus.h" @@ -39,7 +40,6 @@ struct wfx_spi_priv { struct spi_device *func; struct wfx_dev *core; struct gpio_desc *gpio_reset; - struct work_struct request_rx; bool need_swab; }; @@ -140,25 +140,30 @@ static irqreturn_t wfx_spi_irq_handler(int irq, void *priv) { struct wfx_spi_priv *bus = priv; - if (!bus->core) { - WARN(!bus->core, "race condition in driver init/deinit"); - return IRQ_NONE; - } - queue_work(system_highpri_wq, &bus->request_rx); + wfx_bh_request_rx(bus->core); return IRQ_HANDLED; } -static void wfx_spi_request_rx(struct work_struct *work) +static int wfx_spi_irq_subscribe(void *priv) { - struct wfx_spi_priv *bus = - container_of(work, struct wfx_spi_priv, request_rx); - - wfx_bh_request_rx(bus->core); + struct wfx_spi_priv *bus = priv; + u32 flags; + + flags = irq_get_trigger_type(bus->func->irq); + if (!flags) + flags = IRQF_TRIGGER_HIGH; + flags |= IRQF_ONESHOT; + return devm_request_threaded_irq(&bus->func->dev, bus->func->irq, NULL, + wfx_spi_irq_handler, IRQF_ONESHOT, + "wfx", bus); } -static void wfx_flush_irq_work(void *w) +static int wfx_spi_irq_unsubscribe(void *priv) { - flush_work(w); + struct wfx_spi_priv *bus = priv; + + devm_free_irq(&bus->func->dev, bus->func->irq, bus); + return 0; } static size_t wfx_spi_align_size(void *priv, size_t size) @@ -170,6 +175,8 @@ static size_t wfx_spi_align_size(void *priv, size_t size) static const struct hwbus_ops wfx_spi_hwbus_ops = { .copy_from_io = wfx_spi_copy_from_io, .copy_to_io = wfx_spi_copy_to_io, + .irq_subscribe = wfx_spi_irq_subscribe, + .irq_unsubscribe = wfx_spi_irq_unsubscribe, .lock = wfx_spi_lock, .unlock = wfx_spi_unlock, .align_size = wfx_spi_align_size, @@ -216,22 +223,11 @@ static int wfx_spi_probe(struct spi_device *func) usleep_range(2000, 2500); } - INIT_WORK(&bus->request_rx, wfx_spi_request_rx); bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata, &wfx_spi_hwbus_ops, bus); if (!bus->core) return -EIO; - ret = devm_add_action_or_reset(&func->dev, wfx_flush_irq_work, - &bus->request_rx); - if (ret) - return ret; - - ret = devm_request_irq(&func->dev, func->irq, wfx_spi_irq_handler, - IRQF_TRIGGER_RISING, "wfx", bus); - if (ret) - return ret; - return wfx_probe(bus->core); } diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c index c5b83fedeb55..0e959ebc38b5 100644 --- a/drivers/staging/wfx/data_rx.c +++ b/drivers/staging/wfx/data_rx.c @@ -49,7 +49,7 @@ static int wfx_drop_encrypt_data(struct wfx_dev *wdev, } /* Firmware strips ICV in case of MIC failure. */ - if (arg->status == HIF_STATUS_MICFAILURE) + if (arg->status == HIF_STATUS_RX_FAIL_MIC) icv_len = 0; if (skb->len < hdrlen + iv_len + icv_len) { @@ -79,7 +79,7 @@ void wfx_rx_cb(struct wfx_vif *wvif, ieee80211_is_beacon(frame->frame_control))) goto drop; - if (arg->status == HIF_STATUS_MICFAILURE) + if (arg->status == HIF_STATUS_RX_FAIL_MIC) hdr->flag |= RX_FLAG_MMIC_ERROR; else if (arg->status) goto drop; @@ -118,18 +118,6 @@ void wfx_rx_cb(struct wfx_vif *wvif, arg->rx_flags.match_uc_addr && mgmt->u.action.category == WLAN_CATEGORY_BACK) goto drop; - if (ieee80211_is_beacon(frame->frame_control) && - !arg->status && wvif->vif && - ether_addr_equal(ieee80211_get_SA(frame), - wvif->vif->bss_conf.bssid)) { - /* Disable beacon filter once we're associated... */ - if (wvif->disable_beacon_filter && - (wvif->vif->bss_conf.assoc || - wvif->vif->bss_conf.ibss_joined)) { - wvif->disable_beacon_filter = false; - schedule_work(&wvif->update_filtering_work); - } - } ieee80211_rx_irqsafe(wvif->wdev->hw, skb); return; diff --git a/drivers/staging/wfx/data_rx.h b/drivers/staging/wfx/data_rx.h index 61c28bfd2a37..125dbfc1f875 100644 --- a/drivers/staging/wfx/data_rx.h +++ b/drivers/staging/wfx/data_rx.h @@ -8,10 +8,9 @@ #ifndef WFX_DATA_RX_H #define WFX_DATA_RX_H -#include "hif_api_cmd.h" - struct wfx_vif; struct sk_buff; +struct hif_ind_rx; void wfx_rx_cb(struct wfx_vif *wvif, const struct hif_ind_rx *arg, struct sk_buff *skb); diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c index 42183c70d4df..f042ef36b408 100644 --- a/drivers/staging/wfx/data_tx.c +++ b/drivers/staging/wfx/data_tx.c @@ -6,6 +6,7 @@ * Copyright (c) 2010, ST-Ericsson */ #include <net/mac80211.h> +#include <linux/etherdevice.h> #include "data_tx.h" #include "wfx.h" @@ -16,12 +17,11 @@ #include "traces.h" #include "hif_tx_mib.h" -#define WFX_INVALID_RATE_ID 15 -#define WFX_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ)) - static int wfx_get_hw_rate(struct wfx_dev *wdev, const struct ieee80211_tx_rate *rate) { + struct ieee80211_supported_band *band; + if (rate->idx < 0) return -1; if (rate->flags & IEEE80211_TX_RC_MCS) { @@ -33,7 +33,8 @@ static int wfx_get_hw_rate(struct wfx_dev *wdev, } // WFx only support 2GHz, else band information should be retrieved // from ieee80211_tx_info - return wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->bitrates[rate->idx].hw_value; + band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; + return band->bitrates[rate->idx].hw_value; } /* TX policy cache implementation */ @@ -41,73 +42,13 @@ static int wfx_get_hw_rate(struct wfx_dev *wdev, static void wfx_tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy, struct ieee80211_tx_rate *rates) { - int i; - size_t count; struct wfx_dev *wdev = wvif->wdev; + int i, rateid; + u8 count; WARN(rates[0].idx < 0, "invalid rate policy"); memset(policy, 0, sizeof(*policy)); - for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) - if (rates[i].idx < 0) - break; - count = i; - - /* HACK!!! Device has problems (at least) switching from - * 54Mbps CTS to 1Mbps. This switch takes enormous amount - * of time (100-200 ms), leading to valuable throughput drop. - * As a workaround, additional g-rates are injected to the - * policy. - */ - if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) && - rates[0].idx > 4 && rates[0].count > 2 && - rates[1].idx < 2) { - int mid_rate = (rates[0].idx + 4) >> 1; - - /* Decrease number of retries for the initial rate */ - rates[0].count -= 2; - - if (mid_rate != 4) { - /* Keep fallback rate at 1Mbps. */ - rates[3] = rates[1]; - - /* Inject 1 transmission on lowest g-rate */ - rates[2].idx = 4; - rates[2].count = 1; - rates[2].flags = rates[1].flags; - - /* Inject 1 transmission on mid-rate */ - rates[1].idx = mid_rate; - rates[1].count = 1; - - /* Fallback to 1 Mbps is a really bad thing, - * so let's try to increase probability of - * successful transmission on the lowest g rate - * even more - */ - if (rates[0].count >= 3) { - --rates[0].count; - ++rates[2].count; - } - - /* Adjust amount of rates defined */ - count += 2; - } else { - /* Keep fallback rate at 1Mbps. */ - rates[2] = rates[1]; - - /* Inject 2 transmissions on lowest g-rate */ - rates[1].idx = 4; - rates[1].count = 2; - - /* Adjust amount of rates defined */ - count += 1; - } - } - for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { - int rateid; - u8 count; - if (rates[i].idx < 0) break; WARN_ON(rates[i].count > 15); @@ -158,8 +99,7 @@ static int wfx_tx_policy_release(struct tx_policy_cache *cache, } static int wfx_tx_policy_get(struct wfx_vif *wvif, - struct ieee80211_tx_rate *rates, - bool *renew) + struct ieee80211_tx_rate *rates, bool *renew) { int idx; struct tx_policy_cache *cache = &wvif->tx_policy_cache; @@ -171,7 +111,7 @@ static int wfx_tx_policy_get(struct wfx_vif *wvif, if (list_empty(&cache->free)) { WARN(1, "unable to get a valid Tx policy"); spin_unlock_bh(&cache->lock); - return WFX_INVALID_RATE_ID; + return HIF_TX_RETRY_POLICY_INVALID; } idx = wfx_tx_policy_find(cache, &wanted); if (idx >= 0) { @@ -189,10 +129,8 @@ static int wfx_tx_policy_get(struct wfx_vif *wvif, idx = entry - cache->cache; } wfx_tx_policy_use(cache, &cache->cache[idx]); - if (list_empty(&cache->free)) { - /* Lock TX queues. */ - wfx_tx_queues_lock(wvif->wdev); - } + if (list_empty(&cache->free)) + ieee80211_stop_queues(wvif->wdev->hw); spin_unlock_bh(&cache->lock); return idx; } @@ -202,15 +140,13 @@ static void wfx_tx_policy_put(struct wfx_vif *wvif, int idx) int usage, locked; struct tx_policy_cache *cache = &wvif->tx_policy_cache; - if (idx == WFX_INVALID_RATE_ID) + if (idx == HIF_TX_RETRY_POLICY_INVALID) return; spin_lock_bh(&cache->lock); locked = list_empty(&cache->free); usage = wfx_tx_policy_release(cache, &cache->cache[idx]); - if (locked && !usage) { - /* Unlock TX queues. */ - wfx_tx_queues_unlock(wvif->wdev); - } + if (locked && !usage) + ieee80211_wake_queues(wvif->wdev->hw); spin_unlock_bh(&cache->lock); } @@ -218,15 +154,17 @@ static int wfx_tx_policy_upload(struct wfx_vif *wvif) { struct tx_policy *policies = wvif->tx_policy_cache.cache; u8 tmp_rates[12]; - int i; + int i, is_used; do { spin_lock_bh(&wvif->tx_policy_cache.lock); - for (i = 0; i < HIF_MIB_NUM_TX_RATE_RETRY_POLICIES; ++i) - if (!policies[i].uploaded && - memzcmp(policies[i].rates, sizeof(policies[i].rates))) + for (i = 0; i < ARRAY_SIZE(wvif->tx_policy_cache.cache); ++i) { + is_used = memzcmp(policies[i].rates, + sizeof(policies[i].rates)); + if (!policies[i].uploaded && is_used) break; - if (i < HIF_MIB_NUM_TX_RATE_RETRY_POLICIES) { + } + if (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)) { policies[i].uploaded = true; memcpy(tmp_rates, policies[i].rates, sizeof(tmp_rates)); spin_unlock_bh(&wvif->tx_policy_cache.lock); @@ -234,7 +172,7 @@ static int wfx_tx_policy_upload(struct wfx_vif *wvif) } else { spin_unlock_bh(&wvif->tx_policy_cache.lock); } - } while (i < HIF_MIB_NUM_TX_RATE_RETRY_POLICIES); + } while (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)); return 0; } @@ -244,9 +182,7 @@ void wfx_tx_policy_upload_work(struct work_struct *work) container_of(work, struct wfx_vif, tx_policy_upload_work); wfx_tx_policy_upload(wvif); - wfx_tx_unlock(wvif->wdev); - wfx_tx_queues_unlock(wvif->wdev); } void wfx_tx_policy_init(struct wfx_vif *wvif) @@ -260,7 +196,7 @@ void wfx_tx_policy_init(struct wfx_vif *wvif) INIT_LIST_HEAD(&cache->used); INIT_LIST_HEAD(&cache->free); - for (i = 0; i < HIF_MIB_NUM_TX_RATE_RETRY_POLICIES; ++i) + for (i = 0; i < ARRAY_SIZE(cache->cache); ++i) list_add(&cache->cache[i].link, &cache->free); } @@ -281,16 +217,11 @@ static void wfx_tx_manage_pm(struct wfx_vif *wvif, struct ieee80211_hdr *hdr, struct wfx_tx_priv *tx_priv, struct ieee80211_sta *sta) { - u32 mask = ~BIT(tx_priv->raw_link_id); struct wfx_sta_priv *sta_priv; int tid = ieee80211_get_tid(hdr); - spin_lock_bh(&wvif->ps_state_lock); - if (ieee80211_is_auth(hdr->frame_control)) - wvif->sta_asleep_mask &= mask; - spin_unlock_bh(&wvif->ps_state_lock); - if (sta) { + tx_priv->has_sta = true; sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; spin_lock_bh(&sta_priv->lock); sta_priv->buffered[tid]++; @@ -299,9 +230,8 @@ static void wfx_tx_manage_pm(struct wfx_vif *wvif, struct ieee80211_hdr *hdr, } } -static u8 wfx_tx_get_raw_link_id(struct wfx_vif *wvif, - struct ieee80211_sta *sta, - struct ieee80211_hdr *hdr) +static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct ieee80211_hdr *hdr) { struct wfx_sta_priv *sta_priv = sta ? (struct wfx_sta_priv *)&sta->drv_priv : NULL; @@ -313,7 +243,7 @@ static u8 wfx_tx_get_raw_link_id(struct wfx_vif *wvif, return 0; if (is_multicast_ether_addr(da)) return 0; - return WFX_LINK_ID_NO_ASSOC; + return HIF_LINK_ID_NOT_ASSOCIATED; } static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates) @@ -358,7 +288,8 @@ static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates) if (rates[i].idx == -1) { rates[i].idx = 0; rates[i].count = 8; // == hw->max_rate_tries - rates[i].flags = rates[i - 1].flags & IEEE80211_TX_RC_MCS; + rates[i].flags = rates[i - 1].flags & + IEEE80211_TX_RC_MCS; break; } } @@ -375,24 +306,19 @@ static u8 wfx_tx_get_rate_id(struct wfx_vif *wvif, rate_id = wfx_tx_policy_get(wvif, tx_info->driver_rates, &tx_policy_renew); - if (rate_id == WFX_INVALID_RATE_ID) + if (rate_id == HIF_TX_RETRY_POLICY_INVALID) dev_warn(wvif->wdev->dev, "unable to get a valid Tx policy"); if (tx_policy_renew) { - /* FIXME: It's not so optimal to stop TX queues every now and - * then. Better to reimplement task scheduling with a counter. - */ wfx_tx_lock(wvif->wdev); - wfx_tx_queues_lock(wvif->wdev); - if (!schedule_work(&wvif->tx_policy_upload_work)) { - wfx_tx_queues_unlock(wvif->wdev); + if (!schedule_work(&wvif->tx_policy_upload_work)) wfx_tx_unlock(wvif->wdev); - } } return rate_id; } -static struct hif_ht_tx_parameters wfx_tx_get_tx_parms(struct wfx_dev *wdev, struct ieee80211_tx_info *tx_info) +static struct hif_ht_tx_parameters wfx_tx_get_tx_parms(struct wfx_dev *wdev, + struct ieee80211_tx_info *tx_info) { struct ieee80211_tx_rate *rate = &tx_info->driver_rates[0]; struct hif_ht_tx_parameters ret = { }; @@ -429,7 +355,7 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - int queue_id = tx_info->hw_queue; + int queue_id = skb_get_queue_mapping(skb); size_t offset = (size_t)skb->data & 3; int wmsg_len = sizeof(struct hif_msg) + sizeof(struct hif_req_tx) + offset; @@ -441,14 +367,8 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, memset(tx_info->rate_driver_data, 0, sizeof(struct wfx_tx_priv)); // Fill tx_priv tx_priv = (struct wfx_tx_priv *)tx_info->rate_driver_data; - tx_priv->raw_link_id = wfx_tx_get_raw_link_id(wvif, sta, hdr); - tx_priv->link_id = tx_priv->raw_link_id; if (ieee80211_has_protected(hdr->frame_control)) tx_priv->hw_key = hw_key; - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - tx_priv->link_id = WFX_LINK_ID_AFTER_DTIM; - if (sta && (sta->uapsd_queues & BIT(queue_id))) - tx_priv->link_id = WFX_LINK_ID_UAPSD; // Fill hif_msg WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb"); @@ -461,7 +381,8 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, hif_msg->id = HIF_REQ_ID_TX; hif_msg->interface = wvif->id; if (skb->len > wvif->wdev->hw_caps.size_inp_ch_buf) { - dev_warn(wvif->wdev->dev, "requested frame size (%d) is larger than maximum supported (%d)\n", + dev_warn(wvif->wdev->dev, + "requested frame size (%d) is larger than maximum supported (%d)\n", skb->len, wvif->wdev->hw_caps.size_inp_ch_buf); skb_pull(skb, wmsg_len); return -EIO; @@ -472,13 +393,14 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, // packet_id just need to be unique on device. 32bits are more than // necessary for that task, so we tae advantage of it to add some extra // data for debug. - req->packet_id = queue_id << 28 | - IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)) << 16 | - (atomic_add_return(1, &wvif->wdev->packet_id) & 0xFFFF); + req->packet_id = atomic_add_return(1, &wvif->wdev->packet_id) & 0xFFFF; + req->packet_id |= IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)) << 16; + req->packet_id |= queue_id << 28; + req->data_flags.fc_offset = offset; if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) req->data_flags.after_dtim = 1; - req->queue_id.peer_sta_id = tx_priv->raw_link_id; + req->queue_id.peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr); // Queue index are inverted between firmware and Linux req->queue_id.queue_id = 3 - queue_id; req->ht_tx_parameters = wfx_tx_get_tx_parms(wvif->wdev, tx_info); @@ -486,7 +408,7 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, // Auxiliary operations wfx_tx_manage_pm(wvif, hdr, tx_priv, sta); - wfx_tx_queue_put(wvif->wdev, &wvif->wdev->tx_queue[queue_id], skb); + wfx_tx_queues_put(wvif->wdev, skb); if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) schedule_work(&wvif->update_tim_work); wfx_bh_request_tx(wvif->wdev); @@ -528,28 +450,59 @@ drop: ieee80211_tx_status_irqsafe(wdev->hw, skb); } -void wfx_tx_confirm_cb(struct wfx_vif *wvif, const struct hif_cnf_tx *arg) +static struct ieee80211_hdr *wfx_skb_hdr80211(struct sk_buff *skb) { - int i; - int tx_count; - struct sk_buff *skb; - struct ieee80211_tx_rate *rate; - struct ieee80211_tx_info *tx_info; - const struct wfx_tx_priv *tx_priv; + struct hif_msg *hif = (struct hif_msg *)skb->data; + struct hif_req_tx *req = (struct hif_req_tx *)hif->body; - skb = wfx_pending_get(wvif->wdev, arg->packet_id); - if (!skb) { - dev_warn(wvif->wdev->dev, - "received unknown packet_id (%#.8x) from chip\n", - arg->packet_id); - return; + return (struct ieee80211_hdr *)(req->frame + req->data_flags.fc_offset); +} + +static void wfx_tx_update_sta(struct wfx_vif *wvif, struct ieee80211_hdr *hdr) +{ + int tid = ieee80211_get_tid(hdr); + struct wfx_sta_priv *sta_priv; + struct ieee80211_sta *sta; + + rcu_read_lock(); // protect sta + sta = ieee80211_find_sta(wvif->vif, hdr->addr1); + if (sta) { + sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; + spin_lock_bh(&sta_priv->lock); + WARN(!sta_priv->buffered[tid], "inconsistent notification"); + sta_priv->buffered[tid]--; + if (!sta_priv->buffered[tid]) + ieee80211_sta_set_buffered(sta, tid, false); + spin_unlock_bh(&sta_priv->lock); + } else { + dev_dbg(wvif->wdev->dev, "%s: sta does not exist anymore\n", + __func__); } - tx_info = IEEE80211_SKB_CB(skb); - tx_priv = wfx_skb_tx_priv(skb); - _trace_tx_stats(arg, skb, - wfx_pending_get_pkt_us_delay(wvif->wdev, skb)); + rcu_read_unlock(); +} + +static void wfx_skb_dtor(struct wfx_vif *wvif, struct sk_buff *skb) +{ + struct hif_msg *hif = (struct hif_msg *)skb->data; + struct hif_req_tx *req = (struct hif_req_tx *)hif->body; + unsigned int offset = sizeof(struct hif_msg) + + sizeof(struct hif_req_tx) + + req->data_flags.fc_offset; + + WARN_ON(!wvif); + wfx_tx_policy_put(wvif, req->tx_flags.retry_policy_index); + skb_pull(skb, offset); + ieee80211_tx_status_irqsafe(wvif->wdev->hw, skb); +} + +static void wfx_tx_fill_rates(struct wfx_dev *wdev, + struct ieee80211_tx_info *tx_info, + const struct hif_cnf_tx *arg) +{ + struct ieee80211_tx_rate *rate; + int tx_count; + int i; - // You can touch to tx_priv, but don't touch to tx_info->status. tx_count = arg->ack_failures; if (!arg->status || arg->ack_failures) tx_count += 1; // Also report success @@ -558,16 +511,14 @@ void wfx_tx_confirm_cb(struct wfx_vif *wvif, const struct hif_cnf_tx *arg) if (rate->idx < 0) break; if (tx_count < rate->count && - arg->status == HIF_STATUS_RETRY_EXCEEDED && + arg->status == HIF_STATUS_TX_FAIL_RETRIES && arg->ack_failures) - dev_dbg(wvif->wdev->dev, "all retries were not consumed: %d != %d\n", + dev_dbg(wdev->dev, "all retries were not consumed: %d != %d\n", rate->count, tx_count); if (tx_count <= rate->count && tx_count && - arg->txed_rate != wfx_get_hw_rate(wvif->wdev, rate)) - dev_dbg(wvif->wdev->dev, - "inconsistent tx_info rates: %d != %d\n", - arg->txed_rate, - wfx_get_hw_rate(wvif->wdev, rate)); + arg->txed_rate != wfx_get_hw_rate(wdev, rate)) + dev_dbg(wdev->dev, "inconsistent tx_info rates: %d != %d\n", + arg->txed_rate, wfx_get_hw_rate(wdev, rate)); if (tx_count > rate->count) { tx_count -= rate->count; } else if (!tx_count) { @@ -579,8 +530,30 @@ void wfx_tx_confirm_cb(struct wfx_vif *wvif, const struct hif_cnf_tx *arg) } } if (tx_count) - dev_dbg(wvif->wdev->dev, - "%d more retries than expected\n", tx_count); + dev_dbg(wdev->dev, "%d more retries than expected\n", tx_count); +} + +void wfx_tx_confirm_cb(struct wfx_vif *wvif, const struct hif_cnf_tx *arg) +{ + struct ieee80211_tx_info *tx_info; + const struct wfx_tx_priv *tx_priv; + struct sk_buff *skb; + + skb = wfx_pending_get(wvif->wdev, arg->packet_id); + if (!skb) { + dev_warn(wvif->wdev->dev, "received unknown packet_id (%#.8x) from chip\n", + arg->packet_id); + return; + } + tx_info = IEEE80211_SKB_CB(skb); + tx_priv = wfx_skb_tx_priv(skb); + _trace_tx_stats(arg, skb, + wfx_pending_get_pkt_us_delay(wvif->wdev, skb)); + + // You can touch to tx_priv, but don't touch to tx_info->status. + wfx_tx_fill_rates(wvif->wdev, tx_info, arg); + if (tx_priv->has_sta) + wfx_tx_update_sta(wvif, wfx_skb_hdr80211(skb)); skb_trim(skb, skb->len - wfx_tx_get_icv_len(tx_priv->hw_key)); // From now, you can touch to tx_info->status, but do not touch to @@ -590,63 +563,64 @@ void wfx_tx_confirm_cb(struct wfx_vif *wvif, const struct hif_cnf_tx *arg) memset(tx_info->pad, 0, sizeof(tx_info->pad)); if (!arg->status) { - if (wvif->bss_loss_state && - arg->packet_id == wvif->bss_loss_confirm_id) - wfx_cqm_bssloss_sm(wvif, 0, 1, 0); tx_info->status.tx_time = - arg->media_delay - arg->tx_queue_delay; + le32_to_cpu(arg->media_delay) - + le32_to_cpu(arg->tx_queue_delay); if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; else tx_info->flags |= IEEE80211_TX_STAT_ACK; - } else if (arg->status == HIF_REQUEUE) { - WARN(!arg->tx_result_flags.requeue, "incoherent status and result_flags"); + } else if (arg->status == HIF_STATUS_TX_FAIL_REQUEUE) { + WARN(!arg->tx_result_flags.requeue, + "incoherent status and result_flags"); if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { wvif->after_dtim_tx_allowed = false; // DTIM period elapsed schedule_work(&wvif->update_tim_work); } tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - } else { - if (wvif->bss_loss_state && - arg->packet_id == wvif->bss_loss_confirm_id) - wfx_cqm_bssloss_sm(wvif, 0, 0, 1); } - wfx_pending_remove(wvif->wdev, skb); + wfx_skb_dtor(wvif, skb); } -static void wfx_notify_buffered_tx(struct wfx_vif *wvif, struct sk_buff *skb) +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_sta *sta; - struct wfx_sta_priv *sta_priv; - int tid = ieee80211_get_tid(hdr); + struct wfx_dev *wdev = hw->priv; + struct sk_buff_head dropped; + struct wfx_queue *queue; + struct wfx_vif *wvif; + struct hif_msg *hif; + struct sk_buff *skb; + int vif_id = -1; + int i; - rcu_read_lock(); // protect sta - sta = ieee80211_find_sta(wvif->vif, hdr->addr1); - if (sta) { - sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; - spin_lock_bh(&sta_priv->lock); - WARN(!sta_priv->buffered[tid], "inconsistent notification"); - sta_priv->buffered[tid]--; - if (!sta_priv->buffered[tid]) - ieee80211_sta_set_buffered(sta, tid, false); - spin_unlock_bh(&sta_priv->lock); + if (vif) + vif_id = ((struct wfx_vif *)vif->drv_priv)->id; + skb_queue_head_init(&dropped); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (!(BIT(i) & queues)) + continue; + queue = &wdev->tx_queue[i]; + if (drop) + wfx_tx_queue_drop(wdev, queue, vif_id, &dropped); + if (wdev->chip_frozen) + continue; + if (wait_event_timeout(wdev->tx_dequeue, + wfx_tx_queue_empty(wdev, queue, vif_id), + msecs_to_jiffies(1000)) <= 0) + dev_warn(wdev->dev, + "frames queued while flushing tx queues?"); + } + wfx_tx_flush(wdev); + if (wdev->chip_frozen) + wfx_pending_drop(wdev, &dropped); + while ((skb = skb_dequeue(&dropped)) != NULL) { + hif = (struct hif_msg *)skb->data; + wvif = wdev_to_wvif(wdev, hif->interface); + if (wfx_skb_tx_priv(skb)->has_sta) + wfx_tx_update_sta(wvif, wfx_skb_hdr80211(skb)); + ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb)); + wfx_skb_dtor(wvif, skb); } - rcu_read_unlock(); } -void wfx_skb_dtor(struct wfx_dev *wdev, struct sk_buff *skb) -{ - struct hif_msg *hif = (struct hif_msg *)skb->data; - struct hif_req_tx *req = (struct hif_req_tx *)hif->body; - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - unsigned int offset = sizeof(struct hif_req_tx) + - sizeof(struct hif_msg) + - req->data_flags.fc_offset; - - WARN_ON(!wvif); - skb_pull(skb, offset); - wfx_notify_buffered_tx(wvif, skb); - wfx_tx_policy_put(wvif, req->tx_flags.retry_policy_index); - ieee80211_tx_status_irqsafe(wdev->hw, skb); -} diff --git a/drivers/staging/wfx/data_tx.h b/drivers/staging/wfx/data_tx.h index c545dd75449b..54fff24508fb 100644 --- a/drivers/staging/wfx/data_tx.h +++ b/drivers/staging/wfx/data_tx.h @@ -26,7 +26,7 @@ struct tx_policy { }; struct tx_policy_cache { - struct tx_policy cache[HIF_MIB_NUM_TX_RATE_RETRY_POLICIES]; + struct tx_policy cache[HIF_TX_RETRY_POLICY_MAX]; // FIXME: use a trees and drop hash from tx_policy struct list_head used; struct list_head free; @@ -36,8 +36,7 @@ struct tx_policy_cache { struct wfx_tx_priv { ktime_t xmit_timestamp; struct ieee80211_key_conf *hw_key; - u8 link_id; - u8 raw_link_id; + bool has_sta; } __packed; void wfx_tx_policy_init(struct wfx_vif *wvif); @@ -46,7 +45,8 @@ void wfx_tx_policy_upload_work(struct work_struct *work); void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); void wfx_tx_confirm_cb(struct wfx_vif *wvif, const struct hif_cnf_tx *arg); -void wfx_skb_dtor(struct wfx_dev *wdev, struct sk_buff *skb); +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); static inline struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb) { diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c index 1164aba118a1..10d649985696 100644 --- a/drivers/staging/wfx/debug.c +++ b/drivers/staging/wfx/debug.c @@ -61,19 +61,26 @@ const char *get_reg_name(unsigned long id) static int wfx_counters_show(struct seq_file *seq, void *v) { - int ret; + int ret, i; struct wfx_dev *wdev = seq->private; - struct hif_mib_extended_count_table counters; + struct hif_mib_extended_count_table counters[3]; + + for (i = 0; i < ARRAY_SIZE(counters); i++) { + ret = hif_get_counters_table(wdev, i, counters + i); + if (ret < 0) + return ret; + if (ret > 0) + return -EIO; + } - ret = hif_get_counters_table(wdev, &counters); - if (ret < 0) - return ret; - if (ret > 0) - return -EIO; + seq_printf(seq, "%-24s %12s %12s %12s\n", + "", "global", "iface 0", "iface 1"); #define PUT_COUNTER(name) \ - seq_printf(seq, "%24s %d\n", #name ":",\ - le32_to_cpu(counters.count_##name)) + seq_printf(seq, "%-24s %12d %12d %12d\n", #name, \ + le32_to_cpu(counters[2].count_##name), \ + le32_to_cpu(counters[0].count_##name), \ + le32_to_cpu(counters[1].count_##name)) PUT_COUNTER(tx_packets); PUT_COUNTER(tx_multicast_frames); @@ -105,6 +112,12 @@ static int wfx_counters_show(struct seq_file *seq, void *v) #undef PUT_COUNTER + for (i = 0; i < ARRAY_SIZE(counters[0].reserved); i++) + seq_printf(seq, "reserved[%02d]%12s %12d %12d %12d\n", i, "", + le32_to_cpu(counters[2].reserved[i]), + le32_to_cpu(counters[0].reserved[i]), + le32_to_cpu(counters[1].reserved[i])); + return 0; } DEFINE_SHOW_ATTRIBUTE(wfx_counters); @@ -142,7 +155,7 @@ static int wfx_rx_stats_show(struct seq_file *seq, void *v) mutex_lock(&wdev->rx_stats_lock); seq_printf(seq, "Timestamp: %dus\n", st->date); seq_printf(seq, "Low power clock: frequency %uHz, external %s\n", - st->pwr_clk_freq, + le32_to_cpu(st->pwr_clk_freq), st->is_ext_pwr_clk ? "yes" : "no"); seq_printf(seq, "Num. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n", @@ -152,9 +165,12 @@ static int wfx_rx_stats_show(struct seq_file *seq, void *v) for (i = 0; i < ARRAY_SIZE(channel_names); i++) { if (channel_names[i]) seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n", - channel_names[i], st->nb_rx_by_rate[i], - st->per[i], st->rssi[i] / 100, - st->snr[i] / 100, st->cfo[i]); + channel_names[i], + le32_to_cpu(st->nb_rx_by_rate[i]), + le16_to_cpu(st->per[i]), + (s16)le16_to_cpu(st->rssi[i]) / 100, + (s16)le16_to_cpu(st->snr[i]) / 100, + (s16)le16_to_cpu(st->cfo[i])); } mutex_unlock(&wdev->rx_stats_lock); @@ -162,6 +178,30 @@ static int wfx_rx_stats_show(struct seq_file *seq, void *v) } DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats); +static int wfx_tx_power_loop_show(struct seq_file *seq, void *v) +{ + struct wfx_dev *wdev = seq->private; + struct hif_tx_power_loop_info *st = &wdev->tx_power_loop_info; + int tmp; + + mutex_lock(&wdev->tx_power_loop_info_lock); + tmp = le16_to_cpu(st->tx_gain_dig); + seq_printf(seq, "Tx gain digital: %d\n", tmp); + tmp = le16_to_cpu(st->tx_gain_pa); + seq_printf(seq, "Tx gain PA: %d\n", tmp); + tmp = (s16)le16_to_cpu(st->target_pout); + seq_printf(seq, "Target Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); + tmp = (s16)le16_to_cpu(st->p_estimation); + seq_printf(seq, "FEM Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); + tmp = le16_to_cpu(st->vpdet); + seq_printf(seq, "Vpdet: %d mV\n", tmp); + seq_printf(seq, "Measure index: %d\n", st->measurement_index); + mutex_unlock(&wdev->tx_power_loop_info_lock); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_tx_power_loop); + static ssize_t wfx_send_pds_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -234,7 +274,7 @@ static ssize_t wfx_send_hif_msg_write(struct file *file, request = memdup_user(user_buf, count); if (IS_ERR(request)) return PTR_ERR(request); - if (request->len != count) { + if (le16_to_cpu(request->len) != count) { kfree(request); return -EINVAL; } @@ -301,6 +341,8 @@ int wfx_debug_init(struct wfx_dev *wdev) d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir); debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops); debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops); + debugfs_create_file("tx_power_loop", 0444, d, wdev, + &wfx_tx_power_loop_fops); debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops); debugfs_create_file("burn_slk_key", 0200, d, wdev, &wfx_burn_slk_key_fops); diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c index 9d61082c1e6c..72bb3d2a9613 100644 --- a/drivers/staging/wfx/fwio.c +++ b/drivers/staging/wfx/fwio.c @@ -99,16 +99,16 @@ static int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf, return ret; } -int get_firmware(struct wfx_dev *wdev, u32 keyset_chip, - const struct firmware **fw, int *file_offset) +static int get_firmware(struct wfx_dev *wdev, u32 keyset_chip, + const struct firmware **fw, int *file_offset) { int keyset_file; char filename[256]; const char *data; int ret; - snprintf(filename, sizeof(filename), "%s_%02X.sec", wdev->pdata.file_fw, - keyset_chip); + snprintf(filename, sizeof(filename), "%s_%02X.sec", + wdev->pdata.file_fw, keyset_chip); ret = firmware_request_nowarn(fw, filename, wdev->dev); if (ret) { dev_info(wdev->dev, "can't load %s, falling back to %s.sec\n", @@ -325,8 +325,8 @@ static int init_gpr(struct wfx_dev *wdev) gpr_init[i].value); if (ret < 0) return ret; - dev_dbg(wdev->dev, " index %02x: %08x\n", gpr_init[i].index, - gpr_init[i].value); + dev_dbg(wdev->dev, " index %02x: %08x\n", + gpr_init[i].index, gpr_init[i].value); } return 0; } @@ -360,7 +360,7 @@ int wfx_init_device(struct wfx_dev *wdev) dev_dbg(wdev->dev, "initial config register value: %08x\n", reg); hw_revision = FIELD_GET(CFG_DEVICE_ID_MAJOR, reg); - if (hw_revision == 0 || hw_revision > 2) { + if (hw_revision == 0) { dev_err(wdev->dev, "bad hardware revision number: %d\n", hw_revision); return -ENODEV; diff --git a/drivers/staging/wfx/hif_api_cmd.h b/drivers/staging/wfx/hif_api_cmd.h index 071b71e2a107..21cde19cff75 100644 --- a/drivers/staging/wfx/hif_api_cmd.h +++ b/drivers/staging/wfx/hif_api_cmd.h @@ -10,56 +10,54 @@ #include "hif_api_general.h" -#define HIF_NUM_AC 4 - #define HIF_API_SSID_SIZE API_SSID_SIZE enum hif_requests_ids { - HIF_REQ_ID_RESET = 0x0a, - HIF_REQ_ID_READ_MIB = 0x05, - HIF_REQ_ID_WRITE_MIB = 0x06, - HIF_REQ_ID_START_SCAN = 0x07, - HIF_REQ_ID_STOP_SCAN = 0x08, - HIF_REQ_ID_TX = 0x04, - HIF_REQ_ID_JOIN = 0x0b, - HIF_REQ_ID_SET_PM_MODE = 0x10, - HIF_REQ_ID_SET_BSS_PARAMS = 0x11, - HIF_REQ_ID_ADD_KEY = 0x0c, - HIF_REQ_ID_REMOVE_KEY = 0x0d, - HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13, - HIF_REQ_ID_START = 0x17, - HIF_REQ_ID_BEACON_TRANSMIT = 0x18, - HIF_REQ_ID_UPDATE_IE = 0x1b, - HIF_REQ_ID_MAP_LINK = 0x1c, + HIF_REQ_ID_RESET = 0x0a, + HIF_REQ_ID_READ_MIB = 0x05, + HIF_REQ_ID_WRITE_MIB = 0x06, + HIF_REQ_ID_START_SCAN = 0x07, + HIF_REQ_ID_STOP_SCAN = 0x08, + HIF_REQ_ID_TX = 0x04, + HIF_REQ_ID_JOIN = 0x0b, + HIF_REQ_ID_SET_PM_MODE = 0x10, + HIF_REQ_ID_SET_BSS_PARAMS = 0x11, + HIF_REQ_ID_ADD_KEY = 0x0c, + HIF_REQ_ID_REMOVE_KEY = 0x0d, + HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13, + HIF_REQ_ID_START = 0x17, + HIF_REQ_ID_BEACON_TRANSMIT = 0x18, + HIF_REQ_ID_UPDATE_IE = 0x1b, + HIF_REQ_ID_MAP_LINK = 0x1c, }; enum hif_confirmations_ids { - HIF_CNF_ID_RESET = 0x0a, - HIF_CNF_ID_READ_MIB = 0x05, - HIF_CNF_ID_WRITE_MIB = 0x06, - HIF_CNF_ID_START_SCAN = 0x07, - HIF_CNF_ID_STOP_SCAN = 0x08, - HIF_CNF_ID_TX = 0x04, - HIF_CNF_ID_MULTI_TRANSMIT = 0x1e, - HIF_CNF_ID_JOIN = 0x0b, - HIF_CNF_ID_SET_PM_MODE = 0x10, - HIF_CNF_ID_SET_BSS_PARAMS = 0x11, - HIF_CNF_ID_ADD_KEY = 0x0c, - HIF_CNF_ID_REMOVE_KEY = 0x0d, - HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13, - HIF_CNF_ID_START = 0x17, - HIF_CNF_ID_BEACON_TRANSMIT = 0x18, - HIF_CNF_ID_UPDATE_IE = 0x1b, - HIF_CNF_ID_MAP_LINK = 0x1c, + HIF_CNF_ID_RESET = 0x0a, + HIF_CNF_ID_READ_MIB = 0x05, + HIF_CNF_ID_WRITE_MIB = 0x06, + HIF_CNF_ID_START_SCAN = 0x07, + HIF_CNF_ID_STOP_SCAN = 0x08, + HIF_CNF_ID_TX = 0x04, + HIF_CNF_ID_MULTI_TRANSMIT = 0x1e, + HIF_CNF_ID_JOIN = 0x0b, + HIF_CNF_ID_SET_PM_MODE = 0x10, + HIF_CNF_ID_SET_BSS_PARAMS = 0x11, + HIF_CNF_ID_ADD_KEY = 0x0c, + HIF_CNF_ID_REMOVE_KEY = 0x0d, + HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13, + HIF_CNF_ID_START = 0x17, + HIF_CNF_ID_BEACON_TRANSMIT = 0x18, + HIF_CNF_ID_UPDATE_IE = 0x1b, + HIF_CNF_ID_MAP_LINK = 0x1c, }; enum hif_indications_ids { - HIF_IND_ID_RX = 0x84, - HIF_IND_ID_SCAN_CMPL = 0x86, - HIF_IND_ID_JOIN_COMPLETE = 0x8f, - HIF_IND_ID_SET_PM_MODE_CMPL = 0x89, - HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c, - HIF_IND_ID_EVENT = 0x85 + HIF_IND_ID_RX = 0x84, + HIF_IND_ID_SCAN_CMPL = 0x86, + HIF_IND_ID_JOIN_COMPLETE = 0x8f, + HIF_IND_ID_SET_PM_MODE_CMPL = 0x89, + HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c, + HIF_IND_ID_EVENT = 0x85 }; union hif_commands_ids { @@ -68,27 +66,11 @@ union hif_commands_ids { enum hif_indications_ids indication; }; -enum hif_status { - HIF_STATUS_SUCCESS = 0x0, - HIF_STATUS_FAILURE = 0x1, - HIF_INVALID_PARAMETER = 0x2, - HIF_STATUS_WARNING = 0x3, - HIF_ERROR_UNSUPPORTED_MSG_ID = 0x4, - HIF_STATUS_DECRYPTFAILURE = 0x10, - HIF_STATUS_MICFAILURE = 0x11, - HIF_STATUS_NO_KEY_FOUND = 0x12, - HIF_STATUS_RETRY_EXCEEDED = 0x13, - HIF_STATUS_TX_LIFETIME_EXCEEDED = 0x14, - HIF_REQUEUE = 0x15, - HIF_STATUS_REFUSED = 0x16, - HIF_STATUS_BUSY = 0x17 -}; - struct hif_reset_flags { - u8 reset_stat:1; - u8 reset_all_int:1; - u8 reserved1:6; - u8 reserved2[3]; + u8 reset_stat:1; + u8 reset_all_int:1; + u8 reserved1:6; + u8 reserved2[3]; } __packed; struct hif_req_reset { @@ -96,117 +78,101 @@ struct hif_req_reset { } __packed; struct hif_req_read_mib { - u16 mib_id; - u16 reserved; + __le16 mib_id; + __le16 reserved; } __packed; struct hif_cnf_read_mib { - u32 status; - u16 mib_id; - u16 length; - u8 mib_data[]; + __le32 status; + __le16 mib_id; + __le16 length; + u8 mib_data[]; } __packed; struct hif_req_write_mib { - u16 mib_id; - u16 length; - u8 mib_data[]; + __le16 mib_id; + __le16 length; + u8 mib_data[]; } __packed; struct hif_cnf_write_mib { - u32 status; + __le32 status; } __packed; struct hif_ie_flags { - u8 beacon:1; - u8 probe_resp:1; - u8 probe_req:1; - u8 reserved1:5; - u8 reserved2; + u8 beacon:1; + u8 probe_resp:1; + u8 probe_req:1; + u8 reserved1:5; + u8 reserved2; } __packed; struct hif_ie_tlv { - u8 type; - u8 length; - u8 data[]; + u8 type; + u8 length; + u8 data[]; } __packed; struct hif_req_update_ie { struct hif_ie_flags ie_flags; - u16 num_ies; + __le16 num_ies; struct hif_ie_tlv ie[]; } __packed; struct hif_cnf_update_ie { - u32 status; + __le32 status; } __packed; struct hif_scan_type { - u8 type:1; - u8 mode:1; - u8 reserved:6; + u8 type:1; + u8 mode:1; + u8 reserved:6; } __packed; struct hif_scan_flags { - u8 fbg:1; - u8 reserved1:1; - u8 pre:1; - u8 reserved2:5; + u8 fbg:1; + u8 reserved1:1; + u8 pre:1; + u8 reserved2:5; } __packed; struct hif_auto_scan_param { - u16 interval; - u8 reserved; + __le16 interval; + u8 reserved; s8 rssi_thr; } __packed; struct hif_ssid_def { - u32 ssid_length; - u8 ssid[HIF_API_SSID_SIZE]; + __le32 ssid_length; + u8 ssid[HIF_API_SSID_SIZE]; } __packed; #define HIF_API_MAX_NB_SSIDS 2 #define HIF_API_MAX_NB_CHANNELS 14 -struct hif_req_start_scan { - u8 band; - struct hif_scan_type scan_type; - struct hif_scan_flags scan_flags; - u8 max_transmit_rate; - struct hif_auto_scan_param auto_scan_param; - u8 num_of_probe_requests; - u8 probe_delay; - u8 num_of_ssids; - u8 num_of_channels; - u32 min_channel_time; - u32 max_channel_time; - s32 tx_power_level; - u8 ssid_and_channel_lists[]; -} __packed; - struct hif_req_start_scan_alt { - u8 band; + u8 band; struct hif_scan_type scan_type; struct hif_scan_flags scan_flags; - u8 max_transmit_rate; + u8 max_transmit_rate; struct hif_auto_scan_param auto_scan_param; - u8 num_of_probe_requests; - u8 probe_delay; - u8 num_of_ssids; - u8 num_of_channels; - u32 min_channel_time; - u32 max_channel_time; - s32 tx_power_level; + u8 num_of_probe_requests; + u8 probe_delay; + u8 num_of_ssids; + u8 num_of_channels; + __le32 min_channel_time; + __le32 max_channel_time; + __le32 tx_power_level; // signed value struct hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS]; - u8 channel_list[]; + u8 channel_list[]; } __packed; struct hif_cnf_start_scan { - u32 status; + __le32 status; } __packed; struct hif_cnf_stop_scan { - u32 status; + __le32 status; } __packed; enum hif_pm_mode_status { @@ -216,10 +182,10 @@ enum hif_pm_mode_status { }; struct hif_ind_scan_cmpl { - u32 status; - u8 pm_mode; - u8 num_channels_completed; - u16 reserved; + __le32 status; + u8 pm_mode; + u8 num_channels_completed; + __le16 reserved; } __packed; enum hif_queue_id { @@ -241,46 +207,48 @@ enum hif_stbc { }; struct hif_queue { - u8 queue_id:2; - u8 peer_sta_id:4; - u8 reserved:2; + u8 queue_id:2; + u8 peer_sta_id:4; + u8 reserved:2; } __packed; struct hif_data_flags { - u8 more:1; - u8 fc_offset:3; - u8 after_dtim:1; - u8 reserved:3; + u8 more:1; + u8 fc_offset:3; + u8 after_dtim:1; + u8 reserved:3; } __packed; struct hif_tx_flags { - u8 start_exp:1; - u8 reserved:3; - u8 retry_policy_index:4; + u8 start_exp:1; + u8 reserved:3; + u8 retry_policy_index:4; } __packed; struct hif_ht_tx_parameters { - u8 frame_format:4; - u8 fec_coding:1; - u8 short_gi:1; - u8 reserved1:1; - u8 stbc:1; - u8 reserved2; - u8 aggregation:1; - u8 reserved3:7; - u8 reserved4; + u8 frame_format:4; + u8 fec_coding:1; + u8 short_gi:1; + u8 reserved1:1; + u8 stbc:1; + u8 reserved2; + u8 aggregation:1; + u8 reserved3:7; + u8 reserved4; } __packed; struct hif_req_tx { - u32 packet_id; - u8 max_tx_rate; + // packet_id is not interpreted by the device, so it is not necessary to + // declare it little endian + u32 packet_id; + u8 max_tx_rate; struct hif_queue queue_id; struct hif_data_flags data_flags; struct hif_tx_flags tx_flags; - u32 reserved; - u32 expire_time; + __le32 reserved; + __le32 expire_time; struct hif_ht_tx_parameters ht_tx_parameters; - u8 frame[]; + u8 frame[]; } __packed; enum hif_qos_ackplcy { @@ -291,26 +259,29 @@ enum hif_qos_ackplcy { }; struct hif_tx_result_flags { - u8 aggr:1; - u8 requeue:1; - u8 ack_policy:2; - u8 txop_limit:1; - u8 reserved1:3; - u8 reserved2; + u8 aggr:1; + u8 requeue:1; + u8 ack_policy:2; + u8 txop_limit:1; + u8 reserved1:3; + u8 reserved2; } __packed; struct hif_cnf_tx { - u32 status; - u32 packet_id; - u8 txed_rate; - u8 ack_failures; + __le32 status; + // packet_id is copied from struct hif_req_tx without been interpreted + // by the device, so it is not necessary to declare it little endian + u32 packet_id; + u8 txed_rate; + u8 ack_failures; struct hif_tx_result_flags tx_result_flags; - u32 media_delay; - u32 tx_queue_delay; + __le32 media_delay; + __le32 tx_queue_delay; } __packed; struct hif_cnf_multi_transmit { - u32 num_tx_confs; + u8 num_tx_confs; + u8 reserved[3]; struct hif_cnf_tx tx_conf_payload[]; } __packed; @@ -323,147 +294,150 @@ enum hif_ri_flags_encrypt { }; struct hif_rx_flags { - u8 encryp:3; - u8 in_aggr:1; - u8 first_aggr:1; - u8 last_aggr:1; - u8 defrag:1; - u8 beacon:1; - u8 tim:1; - u8 bitmap:1; - u8 match_ssid:1; - u8 match_bssid:1; - u8 more:1; - u8 reserved1:1; - u8 ht:1; - u8 stbc:1; - u8 match_uc_addr:1; - u8 match_mc_addr:1; - u8 match_bc_addr:1; - u8 key_type:1; - u8 key_index:4; - u8 reserved2:1; - u8 peer_sta_id:4; - u8 reserved3:2; - u8 reserved4:1; + u8 encryp:3; + u8 in_aggr:1; + u8 first_aggr:1; + u8 last_aggr:1; + u8 defrag:1; + u8 beacon:1; + u8 tim:1; + u8 bitmap:1; + u8 match_ssid:1; + u8 match_bssid:1; + u8 more:1; + u8 reserved1:1; + u8 ht:1; + u8 stbc:1; + u8 match_uc_addr:1; + u8 match_mc_addr:1; + u8 match_bc_addr:1; + u8 key_type:1; + u8 key_index:4; + u8 reserved2:1; + u8 peer_sta_id:4; + u8 reserved3:2; + u8 reserved4:1; } __packed; struct hif_ind_rx { - u32 status; - u16 channel_number; - u8 rxed_rate; - u8 rcpi_rssi; + __le32 status; + u8 channel_number; + u8 reserved; + u8 rxed_rate; + u8 rcpi_rssi; struct hif_rx_flags rx_flags; - u8 frame[]; + u8 frame[]; } __packed; struct hif_req_edca_queue_params { - u8 queue_id; - u8 reserved1; - u8 aifsn; - u8 reserved2; - u16 cw_min; - u16 cw_max; - u16 tx_op_limit; - u16 allowed_medium_time; - u32 reserved3; + u8 queue_id; + u8 reserved1; + u8 aifsn; + u8 reserved2; + __le16 cw_min; + __le16 cw_max; + __le16 tx_op_limit; + __le16 allowed_medium_time; + __le32 reserved3; } __packed; struct hif_cnf_edca_queue_params { - u32 status; + __le32 status; } __packed; struct hif_join_flags { - u8 reserved1:2; - u8 force_no_beacon:1; - u8 force_with_ind:1; - u8 reserved2:4; + u8 reserved1:2; + u8 force_no_beacon:1; + u8 force_with_ind:1; + u8 reserved2:4; } __packed; struct hif_req_join { - u8 infrastructure_bss_mode:1; - u8 reserved1:7; - u8 band; - u16 channel_number; - u8 bssid[ETH_ALEN]; - u16 atim_window; - u8 short_preamble:1; - u8 reserved2:7; - u8 probe_for_join; - u8 reserved3; + u8 infrastructure_bss_mode:1; + u8 reserved1:7; + u8 band; + u8 channel_number; + u8 reserved; + u8 bssid[ETH_ALEN]; + __le16 atim_window; + u8 short_preamble:1; + u8 reserved2:7; + u8 probe_for_join; + u8 reserved3; struct hif_join_flags join_flags; - u32 ssid_length; - u8 ssid[HIF_API_SSID_SIZE]; - u32 beacon_interval; - u32 basic_rate_set; + __le32 ssid_length; + u8 ssid[HIF_API_SSID_SIZE]; + __le32 beacon_interval; + __le32 basic_rate_set; } __packed; struct hif_cnf_join { - u32 status; + __le32 status; } __packed; struct hif_ind_join_complete { - u32 status; + __le32 status; } __packed; struct hif_bss_flags { - u8 lost_count_only:1; - u8 reserved:7; + u8 lost_count_only:1; + u8 reserved:7; } __packed; struct hif_req_set_bss_params { struct hif_bss_flags bss_flags; - u8 beacon_lost_count; - u16 aid; - u32 operational_rate_set; + u8 beacon_lost_count; + __le16 aid; + __le32 operational_rate_set; } __packed; struct hif_cnf_set_bss_params { - u32 status; + __le32 status; } __packed; struct hif_pm_mode { - u8 enter_psm:1; - u8 reserved:6; - u8 fast_psm:1; + u8 enter_psm:1; + u8 reserved:6; + u8 fast_psm:1; } __packed; struct hif_req_set_pm_mode { struct hif_pm_mode pm_mode; - u8 fast_psm_idle_period; - u8 ap_psm_change_period; - u8 min_auto_ps_poll_period; + u8 fast_psm_idle_period; + u8 ap_psm_change_period; + u8 min_auto_ps_poll_period; } __packed; struct hif_cnf_set_pm_mode { - u32 status; + __le32 status; } __packed; struct hif_ind_set_pm_mode_cmpl { - u32 status; - u8 pm_mode; - u8 reserved[3]; + __le32 status; + u8 pm_mode; + u8 reserved[3]; } __packed; struct hif_req_start { - u8 mode; - u8 band; - u16 channel_number; - u32 reserved1; - u32 beacon_interval; - u8 dtim_period; - u8 short_preamble:1; - u8 reserved2:7; - u8 reserved3; - u8 ssid_length; - u8 ssid[HIF_API_SSID_SIZE]; - u32 basic_rate_set; + u8 mode; + u8 band; + u8 channel_number; + u8 reserved1; + __le32 reserved2; + __le32 beacon_interval; + u8 dtim_period; + u8 short_preamble:1; + u8 reserved3:7; + u8 reserved4; + u8 ssid_length; + u8 ssid[HIF_API_SSID_SIZE]; + __le32 basic_rate_set; } __packed; struct hif_cnf_start { - u32 status; + __le32 status; } __packed; enum hif_beacon { @@ -472,46 +446,49 @@ enum hif_beacon { }; struct hif_req_beacon_transmit { - u8 enable_beaconing; - u8 reserved[3]; + u8 enable_beaconing; + u8 reserved[3]; } __packed; struct hif_cnf_beacon_transmit { - u32 status; + __le32 status; } __packed; +#define HIF_LINK_ID_MAX 14 +#define HIF_LINK_ID_NOT_ASSOCIATED (HIF_LINK_ID_MAX + 1) + enum hif_sta_map_direction { HIF_STA_MAP = 0x0, HIF_STA_UNMAP = 0x1 }; struct hif_map_link_flags { - u8 map_direction:1; - u8 mfpc:1; - u8 reserved:6; + u8 map_direction:1; + u8 mfpc:1; + u8 reserved:6; } __packed; struct hif_req_map_link { - u8 mac_addr[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; struct hif_map_link_flags map_link_flags; - u8 peer_sta_id; + u8 peer_sta_id; } __packed; struct hif_cnf_map_link { - u32 status; + __le32 status; } __packed; struct hif_suspend_resume_flags { - u8 resume:1; - u8 reserved1:2; - u8 bc_mc_only:1; - u8 reserved2:4; - u8 reserved3; + u8 resume:1; + u8 reserved1:2; + u8 bc_mc_only:1; + u8 reserved2:4; + u8 reserved3; } __packed; struct hif_ind_suspend_resume_tx { struct hif_suspend_resume_flags suspend_resume_flags; - u16 peer_sta_set; + __le16 peer_sta_set; } __packed; @@ -541,102 +518,102 @@ enum hif_key_type { }; struct hif_wep_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved; - u8 key_length; - u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; + u8 peer_address[ETH_ALEN]; + u8 reserved; + u8 key_length; + u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; } __packed; struct hif_wep_group_key { - u8 key_id; - u8 key_length; - u8 reserved[2]; - u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; + u8 key_id; + u8 key_length; + u8 reserved[2]; + u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; } __packed; struct hif_tkip_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved[2]; - u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; - u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; - u8 tx_mic_key[HIF_API_TX_MIC_KEY_SIZE]; + u8 peer_address[ETH_ALEN]; + u8 reserved[2]; + u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; + u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; + u8 tx_mic_key[HIF_API_TX_MIC_KEY_SIZE]; } __packed; struct hif_tkip_group_key { - u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; - u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; + u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; + u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; + u8 key_id; + u8 reserved[3]; + u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; } __packed; struct hif_aes_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved[2]; - u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; + u8 peer_address[ETH_ALEN]; + u8 reserved[2]; + u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; } __packed; struct hif_aes_group_key { - u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; + u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; + u8 key_id; + u8 reserved[3]; + u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; } __packed; struct hif_wapi_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 key_id; - u8 reserved; - u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; - u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; + u8 peer_address[ETH_ALEN]; + u8 key_id; + u8 reserved; + u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; + u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; } __packed; struct hif_wapi_group_key { - u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; - u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; + u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; + u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; + u8 key_id; + u8 reserved[3]; } __packed; struct hif_igtk_group_key { - u8 igtk_key_data[HIF_API_IGTK_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 ipn[HIF_API_IPN_SIZE]; + u8 igtk_key_data[HIF_API_IGTK_KEY_DATA_SIZE]; + u8 key_id; + u8 reserved[3]; + u8 ipn[HIF_API_IPN_SIZE]; } __packed; union hif_privacy_key_data { - struct hif_wep_pairwise_key wep_pairwise_key; - struct hif_wep_group_key wep_group_key; - struct hif_tkip_pairwise_key tkip_pairwise_key; - struct hif_tkip_group_key tkip_group_key; - struct hif_aes_pairwise_key aes_pairwise_key; - struct hif_aes_group_key aes_group_key; - struct hif_wapi_pairwise_key wapi_pairwise_key; - struct hif_wapi_group_key wapi_group_key; - struct hif_igtk_group_key igtk_group_key; + struct hif_wep_pairwise_key wep_pairwise_key; + struct hif_wep_group_key wep_group_key; + struct hif_tkip_pairwise_key tkip_pairwise_key; + struct hif_tkip_group_key tkip_group_key; + struct hif_aes_pairwise_key aes_pairwise_key; + struct hif_aes_group_key aes_group_key; + struct hif_wapi_pairwise_key wapi_pairwise_key; + struct hif_wapi_group_key wapi_group_key; + struct hif_igtk_group_key igtk_group_key; }; struct hif_req_add_key { - u8 type; - u8 entry_index; - u8 int_id:2; - u8 reserved1:6; - u8 reserved2; + u8 type; + u8 entry_index; + u8 int_id:2; + u8 reserved1:6; + u8 reserved2; union hif_privacy_key_data key; } __packed; struct hif_cnf_add_key { - u32 status; + __le32 status; } __packed; struct hif_req_remove_key { - u8 entry_index; - u8 reserved[3]; + u8 entry_index; + u8 reserved[3]; } __packed; struct hif_cnf_remove_key { - u32 status; + __le32 status; } __packed; enum hif_event_ind { @@ -656,13 +633,13 @@ enum hif_ps_mode_error { }; union hif_event_data { - u8 rcpi_rssi; - u32 ps_mode_error; - u32 peer_sta_set; + u8 rcpi_rssi; + __le32 ps_mode_error; + __le32 peer_sta_set; }; struct hif_ind_event { - u32 event_id; + __le32 event_id; union hif_event_data event_data; } __packed; diff --git a/drivers/staging/wfx/hif_api_general.h b/drivers/staging/wfx/hif_api_general.h index a069c3a21b4d..dba18a7ae919 100644 --- a/drivers/staging/wfx/hif_api_general.h +++ b/drivers/staging/wfx/hif_api_general.h @@ -17,13 +17,13 @@ #define __packed __attribute__((__packed__)) #endif -#define API_SSID_SIZE 32 +#define API_SSID_SIZE 32 -#define HIF_ID_IS_INDICATION 0x80 -#define HIF_COUNTER_MAX 7 +#define HIF_ID_IS_INDICATION 0x80 +#define HIF_COUNTER_MAX 7 struct hif_msg { - u16 len; + __le16 len; u8 id; u8 reserved:1; u8 interface:2; @@ -33,239 +33,252 @@ struct hif_msg { } __packed; enum hif_general_requests_ids { - HIF_REQ_ID_CONFIGURATION = 0x09, - HIF_REQ_ID_CONTROL_GPIO = 0x26, - HIF_REQ_ID_SET_SL_MAC_KEY = 0x27, - HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS = 0x28, - HIF_REQ_ID_SL_CONFIGURE = 0x29, - HIF_REQ_ID_PREVENT_ROLLBACK = 0x2a, - HIF_REQ_ID_PTA_SETTINGS = 0x2b, - HIF_REQ_ID_PTA_PRIORITY = 0x2c, - HIF_REQ_ID_PTA_STATE = 0x2d, - HIF_REQ_ID_SHUT_DOWN = 0x32, + HIF_REQ_ID_CONFIGURATION = 0x09, + HIF_REQ_ID_CONTROL_GPIO = 0x26, + HIF_REQ_ID_SET_SL_MAC_KEY = 0x27, + HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS = 0x28, + HIF_REQ_ID_SL_CONFIGURE = 0x29, + HIF_REQ_ID_PREVENT_ROLLBACK = 0x2a, + HIF_REQ_ID_PTA_SETTINGS = 0x2b, + HIF_REQ_ID_PTA_PRIORITY = 0x2c, + HIF_REQ_ID_PTA_STATE = 0x2d, + HIF_REQ_ID_SHUT_DOWN = 0x32, }; enum hif_general_confirmations_ids { - HIF_CNF_ID_CONFIGURATION = 0x09, - HIF_CNF_ID_CONTROL_GPIO = 0x26, - HIF_CNF_ID_SET_SL_MAC_KEY = 0x27, - HIF_CNF_ID_SL_EXCHANGE_PUB_KEYS = 0x28, - HIF_CNF_ID_SL_CONFIGURE = 0x29, - HIF_CNF_ID_PREVENT_ROLLBACK = 0x2a, - HIF_CNF_ID_PTA_SETTINGS = 0x2b, - HIF_CNF_ID_PTA_PRIORITY = 0x2c, - HIF_CNF_ID_PTA_STATE = 0x2d, - HIF_CNF_ID_SHUT_DOWN = 0x32, + HIF_CNF_ID_CONFIGURATION = 0x09, + HIF_CNF_ID_CONTROL_GPIO = 0x26, + HIF_CNF_ID_SET_SL_MAC_KEY = 0x27, + HIF_CNF_ID_SL_EXCHANGE_PUB_KEYS = 0x28, + HIF_CNF_ID_SL_CONFIGURE = 0x29, + HIF_CNF_ID_PREVENT_ROLLBACK = 0x2a, + HIF_CNF_ID_PTA_SETTINGS = 0x2b, + HIF_CNF_ID_PTA_PRIORITY = 0x2c, + HIF_CNF_ID_PTA_STATE = 0x2d, + HIF_CNF_ID_SHUT_DOWN = 0x32, }; enum hif_general_indications_ids { - HIF_IND_ID_EXCEPTION = 0xe0, - HIF_IND_ID_STARTUP = 0xe1, - HIF_IND_ID_WAKEUP = 0xe2, - HIF_IND_ID_GENERIC = 0xe3, - HIF_IND_ID_ERROR = 0xe4, - HIF_IND_ID_SL_EXCHANGE_PUB_KEYS = 0xe5 + HIF_IND_ID_EXCEPTION = 0xe0, + HIF_IND_ID_STARTUP = 0xe1, + HIF_IND_ID_WAKEUP = 0xe2, + HIF_IND_ID_GENERIC = 0xe3, + HIF_IND_ID_ERROR = 0xe4, + HIF_IND_ID_SL_EXCHANGE_PUB_KEYS = 0xe5 }; -enum hif_hi_status { - HI_STATUS_SUCCESS = 0x0000, - HI_STATUS_FAILURE = 0x0001, - HI_INVALID_PARAMETER = 0x0002, - HI_STATUS_GPIO_WARNING = 0x0003, - HI_ERROR_UNSUPPORTED_MSG_ID = 0x0004, - SL_MAC_KEY_STATUS_SUCCESS = 0x005A, - SL_MAC_KEY_STATUS_FAILED_KEY_ALREADY_BURNED = 0x006B, - SL_MAC_KEY_STATUS_FAILED_RAM_MODE_NOT_ALLOWED = 0x007C, - SL_MAC_KEY_STATUS_FAILED_UNKNOWN_MODE = 0x008D, - SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS = 0x009E, - SL_PUB_KEY_EXCHANGE_STATUS_FAILED = 0x00AF, - PREVENT_ROLLBACK_CNF_SUCCESS = 0x1234, - PREVENT_ROLLBACK_CNF_WRONG_MAGIC_WORD = 0x1256 -}; +#define HIF_STATUS_SUCCESS (cpu_to_le32(0x0000)) +#define HIF_STATUS_FAIL (cpu_to_le32(0x0001)) +#define HIF_STATUS_INVALID_PARAMETER (cpu_to_le32(0x0002)) +#define HIF_STATUS_WARNING (cpu_to_le32(0x0003)) +#define HIF_STATUS_UNKNOWN_REQUEST (cpu_to_le32(0x0004)) +#define HIF_STATUS_RX_FAIL_DECRYPT (cpu_to_le32(0x0010)) +#define HIF_STATUS_RX_FAIL_MIC (cpu_to_le32(0x0011)) +#define HIF_STATUS_RX_FAIL_NO_KEY (cpu_to_le32(0x0012)) +#define HIF_STATUS_TX_FAIL_RETRIES (cpu_to_le32(0x0013)) +#define HIF_STATUS_TX_FAIL_TIMEOUT (cpu_to_le32(0x0014)) +#define HIF_STATUS_TX_FAIL_REQUEUE (cpu_to_le32(0x0015)) +#define HIF_STATUS_REFUSED (cpu_to_le32(0x0016)) +#define HIF_STATUS_BUSY (cpu_to_le32(0x0017)) +#define HIF_STATUS_SLK_SET_KEY_SUCCESS (cpu_to_le32(0x005A)) +#define HIF_STATUS_SLK_SET_KEY_ALREADY_BURNED (cpu_to_le32(0x006B)) +#define HIF_STATUS_SLK_SET_KEY_DISALLOWED_MODE (cpu_to_le32(0x007C)) +#define HIF_STATUS_SLK_SET_KEY_UNKNOWN_MODE (cpu_to_le32(0x008D)) +#define HIF_STATUS_SLK_NEGO_SUCCESS (cpu_to_le32(0x009E)) +#define HIF_STATUS_SLK_NEGO_FAILED (cpu_to_le32(0x00AF)) +#define HIF_STATUS_ROLLBACK_SUCCESS (cpu_to_le32(0x1234)) +#define HIF_STATUS_ROLLBACK_FAIL (cpu_to_le32(0x1256)) enum hif_api_rate_index { - API_RATE_INDEX_B_1MBPS = 0, - API_RATE_INDEX_B_2MBPS = 1, - API_RATE_INDEX_B_5P5MBPS = 2, - API_RATE_INDEX_B_11MBPS = 3, - API_RATE_INDEX_PBCC_22MBPS = 4, - API_RATE_INDEX_PBCC_33MBPS = 5, - API_RATE_INDEX_G_6MBPS = 6, - API_RATE_INDEX_G_9MBPS = 7, - API_RATE_INDEX_G_12MBPS = 8, - API_RATE_INDEX_G_18MBPS = 9, - API_RATE_INDEX_G_24MBPS = 10, - API_RATE_INDEX_G_36MBPS = 11, - API_RATE_INDEX_G_48MBPS = 12, - API_RATE_INDEX_G_54MBPS = 13, - API_RATE_INDEX_N_6P5MBPS = 14, - API_RATE_INDEX_N_13MBPS = 15, - API_RATE_INDEX_N_19P5MBPS = 16, - API_RATE_INDEX_N_26MBPS = 17, - API_RATE_INDEX_N_39MBPS = 18, - API_RATE_INDEX_N_52MBPS = 19, - API_RATE_INDEX_N_58P5MBPS = 20, - API_RATE_INDEX_N_65MBPS = 21, - API_RATE_NUM_ENTRIES = 22 + API_RATE_INDEX_B_1MBPS = 0, + API_RATE_INDEX_B_2MBPS = 1, + API_RATE_INDEX_B_5P5MBPS = 2, + API_RATE_INDEX_B_11MBPS = 3, + API_RATE_INDEX_PBCC_22MBPS = 4, + API_RATE_INDEX_PBCC_33MBPS = 5, + API_RATE_INDEX_G_6MBPS = 6, + API_RATE_INDEX_G_9MBPS = 7, + API_RATE_INDEX_G_12MBPS = 8, + API_RATE_INDEX_G_18MBPS = 9, + API_RATE_INDEX_G_24MBPS = 10, + API_RATE_INDEX_G_36MBPS = 11, + API_RATE_INDEX_G_48MBPS = 12, + API_RATE_INDEX_G_54MBPS = 13, + API_RATE_INDEX_N_6P5MBPS = 14, + API_RATE_INDEX_N_13MBPS = 15, + API_RATE_INDEX_N_19P5MBPS = 16, + API_RATE_INDEX_N_26MBPS = 17, + API_RATE_INDEX_N_39MBPS = 18, + API_RATE_INDEX_N_52MBPS = 19, + API_RATE_INDEX_N_58P5MBPS = 20, + API_RATE_INDEX_N_65MBPS = 21, + API_RATE_NUM_ENTRIES = 22 }; enum hif_fw_type { - HIF_FW_TYPE_ETF = 0x0, - HIF_FW_TYPE_WFM = 0x1, - HIF_FW_TYPE_WSM = 0x2 + HIF_FW_TYPE_ETF = 0x0, + HIF_FW_TYPE_WFM = 0x1, + HIF_FW_TYPE_WSM = 0x2 }; struct hif_capabilities { - u8 link_mode:2; - u8 reserved1:6; - u8 reserved2; - u8 reserved3; - u8 reserved4; + u8 link_mode:2; + u8 reserved1:6; + u8 reserved2; + u8 reserved3; + u8 reserved4; } __packed; struct hif_otp_regul_sel_mode_info { - u8 region_sel_mode:4; - u8 reserved:4; + u8 region_sel_mode:4; + u8 reserved:4; } __packed; struct hif_otp_phy_info { - u8 phy1_region:3; - u8 phy0_region:3; - u8 otp_phy_ver:2; + u8 phy1_region:3; + u8 phy0_region:3; + u8 otp_phy_ver:2; } __packed; -#define API_OPN_SIZE 14 -#define API_UID_SIZE 8 -#define API_DISABLED_CHANNEL_LIST_SIZE 2 -#define API_FIRMWARE_LABEL_SIZE 128 - struct hif_ind_startup { - u32 status; - u16 hardware_id; - u8 opn[API_OPN_SIZE]; - u8 uid[API_UID_SIZE]; - u16 num_inp_ch_bufs; - u16 size_inp_ch_buf; - u8 num_links_ap; - u8 num_interfaces; - u8 mac_addr[2][ETH_ALEN]; - u8 api_version_minor; - u8 api_version_major; + // As the others, this struct is interpreted as little endian by the + // device. However, this struct is also used by the driver. We prefer to + // declare it in native order and doing byte swap on reception. + __le32 status; + u16 hardware_id; + u8 opn[14]; + u8 uid[8]; + u16 num_inp_ch_bufs; + u16 size_inp_ch_buf; + u8 num_links_ap; + u8 num_interfaces; + u8 mac_addr[2][ETH_ALEN]; + u8 api_version_minor; + u8 api_version_major; struct hif_capabilities capabilities; - u8 firmware_build; - u8 firmware_minor; - u8 firmware_major; - u8 firmware_type; - u8 disabled_channel_list[API_DISABLED_CHANNEL_LIST_SIZE]; + u8 firmware_build; + u8 firmware_minor; + u8 firmware_major; + u8 firmware_type; + u8 disabled_channel_list[2]; struct hif_otp_regul_sel_mode_info regul_sel_mode_info; struct hif_otp_phy_info otp_phy_info; - u32 supported_rate_mask; - u8 firmware_label[API_FIRMWARE_LABEL_SIZE]; + u32 supported_rate_mask; + u8 firmware_label[128]; } __packed; struct hif_ind_wakeup { } __packed; struct hif_req_configuration { - u16 length; - u8 pds_data[]; + __le16 length; + u8 pds_data[]; } __packed; struct hif_cnf_configuration { - u32 status; + __le32 status; } __packed; enum hif_gpio_mode { - HIF_GPIO_MODE_D0 = 0x0, - HIF_GPIO_MODE_D1 = 0x1, - HIF_GPIO_MODE_OD0 = 0x2, - HIF_GPIO_MODE_OD1 = 0x3, - HIF_GPIO_MODE_TRISTATE = 0x4, - HIF_GPIO_MODE_TOGGLE = 0x5, - HIF_GPIO_MODE_READ = 0x6 + HIF_GPIO_MODE_D0 = 0x0, + HIF_GPIO_MODE_D1 = 0x1, + HIF_GPIO_MODE_OD0 = 0x2, + HIF_GPIO_MODE_OD1 = 0x3, + HIF_GPIO_MODE_TRISTATE = 0x4, + HIF_GPIO_MODE_TOGGLE = 0x5, + HIF_GPIO_MODE_READ = 0x6 }; struct hif_req_control_gpio { - u8 gpio_label; - u8 gpio_mode; + u8 gpio_label; + u8 gpio_mode; } __packed; -enum hif_gpio_error { - HIF_GPIO_ERROR_0 = 0x0, - HIF_GPIO_ERROR_1 = 0x1, - HIF_GPIO_ERROR_2 = 0x2 -}; - struct hif_cnf_control_gpio { - u32 status; - u32 value; + __le32 status; + __le32 value; } __packed; enum hif_generic_indication_type { - HIF_GENERIC_INDICATION_TYPE_RAW = 0x0, - HIF_GENERIC_INDICATION_TYPE_STRING = 0x1, - HIF_GENERIC_INDICATION_TYPE_RX_STATS = 0x2 + HIF_GENERIC_INDICATION_TYPE_RAW = 0x0, + HIF_GENERIC_INDICATION_TYPE_STRING = 0x1, + HIF_GENERIC_INDICATION_TYPE_RX_STATS = 0x2, + HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO = 0x3, }; struct hif_rx_stats { - u32 nb_rx_frame; - u32 nb_crc_frame; - u32 per_total; - u32 throughput; - u32 nb_rx_by_rate[API_RATE_NUM_ENTRIES]; - u16 per[API_RATE_NUM_ENTRIES]; - s16 snr[API_RATE_NUM_ENTRIES]; - s16 rssi[API_RATE_NUM_ENTRIES]; - s16 cfo[API_RATE_NUM_ENTRIES]; - u32 date; - u32 pwr_clk_freq; - u8 is_ext_pwr_clk; + __le32 nb_rx_frame; + __le32 nb_crc_frame; + __le32 per_total; + __le32 throughput; + __le32 nb_rx_by_rate[API_RATE_NUM_ENTRIES]; + __le16 per[API_RATE_NUM_ENTRIES]; + __le16 snr[API_RATE_NUM_ENTRIES]; // signed value + __le16 rssi[API_RATE_NUM_ENTRIES]; // signed value + __le16 cfo[API_RATE_NUM_ENTRIES]; // signed value + __le32 date; + __le32 pwr_clk_freq; + u8 is_ext_pwr_clk; s8 current_temp; } __packed; +struct hif_tx_power_loop_info { + __le16 tx_gain_dig; + __le16 tx_gain_pa; + __le16 target_pout; // signed value + __le16 p_estimation; // signed value + __le16 vpdet; + u8 measurement_index; + u8 reserved; +} __packed; + union hif_indication_data { - struct hif_rx_stats rx_stats; - u8 raw_data[1]; + struct hif_rx_stats rx_stats; + struct hif_tx_power_loop_info tx_power_loop_info; + u8 raw_data[1]; }; struct hif_ind_generic { - u32 indication_type; + __le32 indication_type; union hif_indication_data indication_data; } __packed; - -#define HIF_EXCEPTION_DATA_SIZE 124 - -struct hif_ind_exception { - u8 data[HIF_EXCEPTION_DATA_SIZE]; -} __packed; - - enum hif_error { - HIF_ERROR_FIRMWARE_ROLLBACK = 0x0, - HIF_ERROR_FIRMWARE_DEBUG_ENABLED = 0x1, - HIF_ERROR_OUTDATED_SESSION_KEY = 0x2, - HIF_ERROR_INVALID_SESSION_KEY = 0x3, - HIF_ERROR_OOR_VOLTAGE = 0x4, - HIF_ERROR_PDS_VERSION = 0x5, - HIF_ERROR_OOR_TEMPERATURE = 0x6, - HIF_ERROR_REQ_DURING_KEY_EXCHANGE = 0x7, - HIF_ERROR_MULTI_TX_CNF_SECURELINK = 0x8, - HIF_ERROR_SECURELINK_OVERFLOW = 0x9, - HIF_ERROR_SECURELINK_DECRYPTION = 0xa + HIF_ERROR_FIRMWARE_ROLLBACK = 0x00, + HIF_ERROR_FIRMWARE_DEBUG_ENABLED = 0x01, + HIF_ERROR_SLK_OUTDATED_SESSION_KEY = 0x02, + HIF_ERROR_SLK_SESSION_KEY = 0x03, + HIF_ERROR_OOR_VOLTAGE = 0x04, + HIF_ERROR_PDS_PAYLOAD = 0x05, + HIF_ERROR_OOR_TEMPERATURE = 0x06, + HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE = 0x07, + HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED = 0x08, + HIF_ERROR_SLK_OVERFLOW = 0x09, + HIF_ERROR_SLK_DECRYPTION = 0x0a, + HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE = 0x0b, + HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW = 0x0c, + HIF_ERROR_HIF_RX_DATA_TOO_LARGE = 0x0e, + HIF_ERROR_HIF_TX_QUEUE_FULL = 0x0d, + HIF_ERROR_HIF_BUS = 0x0f, + HIF_ERROR_PDS_TESTFEATURE = 0x10, }; struct hif_ind_error { - u32 type; - u8 data[]; + __le32 type; + u8 data[]; +} __packed; + +struct hif_ind_exception { + __le32 type; + u8 data[]; } __packed; enum hif_secure_link_state { - SEC_LINK_UNAVAILABLE = 0x0, - SEC_LINK_RESERVED = 0x1, - SEC_LINK_EVAL = 0x2, - SEC_LINK_ENFORCED = 0x3 + SEC_LINK_UNAVAILABLE = 0x0, + SEC_LINK_RESERVED = 0x1, + SEC_LINK_EVAL = 0x2, + SEC_LINK_ENFORCED = 0x3 }; enum hif_sl_encryption_type { @@ -282,156 +295,70 @@ struct hif_sl_msg_hdr { struct hif_sl_msg { struct hif_sl_msg_hdr hdr; - u16 len; - u8 payload[]; + __le16 len; + u8 payload[]; } __packed; -#define AES_CCM_TAG_SIZE 16 +#define AES_CCM_TAG_SIZE 16 struct hif_sl_tag { - u8 tag[16]; + u8 tag[16]; } __packed; enum hif_sl_mac_key_dest { - SL_MAC_KEY_DEST_OTP = 0x78, - SL_MAC_KEY_DEST_RAM = 0x87 + SL_MAC_KEY_DEST_OTP = 0x78, + SL_MAC_KEY_DEST_RAM = 0x87 }; -#define API_KEY_VALUE_SIZE 32 +#define API_KEY_VALUE_SIZE 32 struct hif_req_set_sl_mac_key { - u8 otp_or_ram; - u8 key_value[API_KEY_VALUE_SIZE]; + u8 otp_or_ram; + u8 key_value[API_KEY_VALUE_SIZE]; } __packed; struct hif_cnf_set_sl_mac_key { - u32 status; + __le32 status; } __packed; -#define API_HOST_PUB_KEY_SIZE 32 -#define API_HOST_PUB_KEY_MAC_SIZE 64 - enum hif_sl_session_key_alg { - HIF_SL_CURVE25519 = 0x01, - HIF_SL_KDF = 0x02 + HIF_SL_CURVE25519 = 0x01, + HIF_SL_KDF = 0x02 }; +#define API_HOST_PUB_KEY_SIZE 32 +#define API_HOST_PUB_KEY_MAC_SIZE 64 + struct hif_req_sl_exchange_pub_keys { - u8 algorithm:2; - u8 reserved1:6; - u8 reserved2[3]; - u8 host_pub_key[API_HOST_PUB_KEY_SIZE]; - u8 host_pub_key_mac[API_HOST_PUB_KEY_MAC_SIZE]; + u8 algorithm:2; + u8 reserved1:6; + u8 reserved2[3]; + u8 host_pub_key[API_HOST_PUB_KEY_SIZE]; + u8 host_pub_key_mac[API_HOST_PUB_KEY_MAC_SIZE]; } __packed; struct hif_cnf_sl_exchange_pub_keys { - u32 status; + __le32 status; } __packed; -#define API_NCP_PUB_KEY_SIZE 32 -#define API_NCP_PUB_KEY_MAC_SIZE 64 +#define API_NCP_PUB_KEY_SIZE 32 +#define API_NCP_PUB_KEY_MAC_SIZE 64 struct hif_ind_sl_exchange_pub_keys { - u32 status; - u8 ncp_pub_key[API_NCP_PUB_KEY_SIZE]; - u8 ncp_pub_key_mac[API_NCP_PUB_KEY_MAC_SIZE]; + __le32 status; + u8 ncp_pub_key[API_NCP_PUB_KEY_SIZE]; + u8 ncp_pub_key_mac[API_NCP_PUB_KEY_MAC_SIZE]; } __packed; -#define API_ENCR_BMP_SIZE 32 - struct hif_req_sl_configure { - u8 encr_bmp[API_ENCR_BMP_SIZE]; - u8 disable_session_key_protection:1; - u8 reserved1:7; - u8 reserved2[3]; + u8 encr_bmp[32]; + u8 disable_session_key_protection:1; + u8 reserved1:7; + u8 reserved2[3]; } __packed; struct hif_cnf_sl_configure { - u32 status; -} __packed; - -struct hif_req_prevent_rollback { - u32 magic_word; -} __packed; - -struct hif_cnf_prevent_rollback { - u32 status; -} __packed; - -enum hif_pta_mode { - PTA_1W_WLAN_MASTER = 0, - PTA_1W_COEX_MASTER = 1, - PTA_2W = 2, - PTA_3W = 3, - PTA_4W = 4 -}; - -enum hif_signal_level { - SIGNAL_LOW = 0, - SIGNAL_HIGH = 1 -}; - -enum hif_coex_type { - COEX_TYPE_GENERIC = 0, - COEX_TYPE_BLE = 1 -}; - -enum hif_grant_state { - NO_GRANT = 0, - GRANT = 1 -}; - -struct hif_req_pta_settings { - u8 pta_mode; - u8 request_signal_active_level; - u8 priority_signal_active_level; - u8 freq_signal_active_level; - u8 grant_signal_active_level; - u8 coex_type; - u8 default_grant_state; - u8 simultaneous_rx_accesses; - u8 priority_sampling_time; - u8 tx_rx_sampling_time; - u8 freq_sampling_time; - u8 grant_valid_time; - u8 fem_control_time; - u8 first_slot_time; - u16 periodic_tx_rx_sampling_time; - u16 coex_quota; - u16 wlan_quota; -} __packed; - -struct hif_cnf_pta_settings { - u32 status; -} __packed; - -enum hif_pta_priority { - HIF_PTA_PRIORITY_COEX_MAXIMIZED = 0x00000562, - HIF_PTA_PRIORITY_COEX_HIGH = 0x00000462, - HIF_PTA_PRIORITY_BALANCED = 0x00001461, - HIF_PTA_PRIORITY_WLAN_HIGH = 0x00001851, - HIF_PTA_PRIORITY_WLAN_MAXIMIZED = 0x00001A51 -}; - -struct hif_req_pta_priority { - u32 priority; -} __packed; - -struct hif_cnf_pta_priority { - u32 status; -} __packed; - -enum hif_pta_state { - PTA_OFF = 0, - PTA_ON = 1 -}; - -struct hif_req_pta_state { - u32 pta_state; -} __packed; - -struct hif_cnf_pta_state { - u32 status; + __le32 status; } __packed; #endif diff --git a/drivers/staging/wfx/hif_api_mib.h b/drivers/staging/wfx/hif_api_mib.h index 0c67cd4c1593..6f1434795fa8 100644 --- a/drivers/staging/wfx/hif_api_mib.h +++ b/drivers/staging/wfx/hif_api_mib.h @@ -10,175 +10,88 @@ #include "hif_api_general.h" -#define HIF_API_IPV4_ADDRESS_SIZE 4 -#define HIF_API_IPV6_ADDRESS_SIZE 16 +#define HIF_API_IPV4_ADDRESS_SIZE 4 +#define HIF_API_IPV6_ADDRESS_SIZE 16 enum hif_mib_ids { - HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE = 0x2000, - HIF_MIB_ID_GL_BLOCK_ACK_INFO = 0x2001, - HIF_MIB_ID_GL_SET_MULTI_MSG = 0x2002, - HIF_MIB_ID_CCA_CONFIG = 0x2003, - HIF_MIB_ID_ETHERTYPE_DATAFRAME_CONDITION = 0x2010, - HIF_MIB_ID_PORT_DATAFRAME_CONDITION = 0x2011, - HIF_MIB_ID_MAGIC_DATAFRAME_CONDITION = 0x2012, - HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION = 0x2013, - HIF_MIB_ID_IPV4_ADDR_DATAFRAME_CONDITION = 0x2014, - HIF_MIB_ID_IPV6_ADDR_DATAFRAME_CONDITION = 0x2015, - HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION = 0x2016, - HIF_MIB_ID_CONFIG_DATA_FILTER = 0x2017, - HIF_MIB_ID_SET_DATA_FILTERING = 0x2018, - HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE = 0x2019, - HIF_MIB_ID_NS_IP_ADDRESSES_TABLE = 0x201A, - HIF_MIB_ID_RX_FILTER = 0x201B, - HIF_MIB_ID_BEACON_FILTER_TABLE = 0x201C, - HIF_MIB_ID_BEACON_FILTER_ENABLE = 0x201D, - HIF_MIB_ID_GRP_SEQ_COUNTER = 0x2030, - HIF_MIB_ID_TSF_COUNTER = 0x2031, - HIF_MIB_ID_STATISTICS_TABLE = 0x2032, - HIF_MIB_ID_COUNTERS_TABLE = 0x2033, - HIF_MIB_ID_MAX_TX_POWER_LEVEL = 0x2034, - HIF_MIB_ID_EXTENDED_COUNTERS_TABLE = 0x2035, - HIF_MIB_ID_DOT11_MAC_ADDRESS = 0x2040, + HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE = 0x2000, + HIF_MIB_ID_GL_BLOCK_ACK_INFO = 0x2001, + HIF_MIB_ID_GL_SET_MULTI_MSG = 0x2002, + HIF_MIB_ID_CCA_CONFIG = 0x2003, + HIF_MIB_ID_ETHERTYPE_DATAFRAME_CONDITION = 0x2010, + HIF_MIB_ID_PORT_DATAFRAME_CONDITION = 0x2011, + HIF_MIB_ID_MAGIC_DATAFRAME_CONDITION = 0x2012, + HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION = 0x2013, + HIF_MIB_ID_IPV4_ADDR_DATAFRAME_CONDITION = 0x2014, + HIF_MIB_ID_IPV6_ADDR_DATAFRAME_CONDITION = 0x2015, + HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION = 0x2016, + HIF_MIB_ID_CONFIG_DATA_FILTER = 0x2017, + HIF_MIB_ID_SET_DATA_FILTERING = 0x2018, + HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE = 0x2019, + HIF_MIB_ID_NS_IP_ADDRESSES_TABLE = 0x201A, + HIF_MIB_ID_RX_FILTER = 0x201B, + HIF_MIB_ID_BEACON_FILTER_TABLE = 0x201C, + HIF_MIB_ID_BEACON_FILTER_ENABLE = 0x201D, + HIF_MIB_ID_GRP_SEQ_COUNTER = 0x2030, + HIF_MIB_ID_TSF_COUNTER = 0x2031, + HIF_MIB_ID_STATISTICS_TABLE = 0x2032, + HIF_MIB_ID_COUNTERS_TABLE = 0x2033, + HIF_MIB_ID_MAX_TX_POWER_LEVEL = 0x2034, + HIF_MIB_ID_EXTENDED_COUNTERS_TABLE = 0x2035, + HIF_MIB_ID_DOT11_MAC_ADDRESS = 0x2040, HIF_MIB_ID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME = 0x2041, - HIF_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME = 0x2042, - HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID = 0x2043, - HIF_MIB_ID_DOT11_RTS_THRESHOLD = 0x2044, - HIF_MIB_ID_SLOT_TIME = 0x2045, - HIF_MIB_ID_CURRENT_TX_POWER_LEVEL = 0x2046, - HIF_MIB_ID_NON_ERP_PROTECTION = 0x2047, - HIF_MIB_ID_TEMPLATE_FRAME = 0x2048, - HIF_MIB_ID_BEACON_WAKEUP_PERIOD = 0x2049, - HIF_MIB_ID_RCPI_RSSI_THRESHOLD = 0x204A, - HIF_MIB_ID_BLOCK_ACK_POLICY = 0x204B, - HIF_MIB_ID_OVERRIDE_INTERNAL_TX_RATE = 0x204C, - HIF_MIB_ID_SET_ASSOCIATION_MODE = 0x204D, - HIF_MIB_ID_SET_UAPSD_INFORMATION = 0x204E, - HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY = 0x204F, - HIF_MIB_ID_PROTECTED_MGMT_POLICY = 0x2050, - HIF_MIB_ID_SET_HT_PROTECTION = 0x2051, - HIF_MIB_ID_KEEP_ALIVE_PERIOD = 0x2052, - HIF_MIB_ID_ARP_KEEP_ALIVE_PERIOD = 0x2053, - HIF_MIB_ID_INACTIVITY_TIMER = 0x2054, - HIF_MIB_ID_INTERFACE_PROTECTION = 0x2055, - HIF_MIB_ID_BEACON_STATS = 0x2056, + HIF_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME = 0x2042, + HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID = 0x2043, + HIF_MIB_ID_DOT11_RTS_THRESHOLD = 0x2044, + HIF_MIB_ID_SLOT_TIME = 0x2045, + HIF_MIB_ID_CURRENT_TX_POWER_LEVEL = 0x2046, + HIF_MIB_ID_NON_ERP_PROTECTION = 0x2047, + HIF_MIB_ID_TEMPLATE_FRAME = 0x2048, + HIF_MIB_ID_BEACON_WAKEUP_PERIOD = 0x2049, + HIF_MIB_ID_RCPI_RSSI_THRESHOLD = 0x204A, + HIF_MIB_ID_BLOCK_ACK_POLICY = 0x204B, + HIF_MIB_ID_OVERRIDE_INTERNAL_TX_RATE = 0x204C, + HIF_MIB_ID_SET_ASSOCIATION_MODE = 0x204D, + HIF_MIB_ID_SET_UAPSD_INFORMATION = 0x204E, + HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY = 0x204F, + HIF_MIB_ID_PROTECTED_MGMT_POLICY = 0x2050, + HIF_MIB_ID_SET_HT_PROTECTION = 0x2051, + HIF_MIB_ID_KEEP_ALIVE_PERIOD = 0x2052, + HIF_MIB_ID_ARP_KEEP_ALIVE_PERIOD = 0x2053, + HIF_MIB_ID_INACTIVITY_TIMER = 0x2054, + HIF_MIB_ID_INTERFACE_PROTECTION = 0x2055, + HIF_MIB_ID_BEACON_STATS = 0x2056, }; -#define HIF_OP_POWER_MODE_MASK 0xf - enum hif_op_power_mode { - HIF_OP_POWER_MODE_ACTIVE = 0x0, - HIF_OP_POWER_MODE_DOZE = 0x1, - HIF_OP_POWER_MODE_QUIESCENT = 0x2 + HIF_OP_POWER_MODE_ACTIVE = 0x0, + HIF_OP_POWER_MODE_DOZE = 0x1, + HIF_OP_POWER_MODE_QUIESCENT = 0x2 }; struct hif_mib_gl_operational_power_mode { - u8 power_mode:4; - u8 reserved1:3; - u8 wup_ind_activation:1; - u8 reserved2[3]; -} __packed; - -struct hif_mib_gl_block_ack_info { - u8 rx_buffer_size; - u8 rx_max_num_agreements; - u8 tx_buffer_size; - u8 tx_max_num_agreements; + u8 power_mode:4; + u8 reserved1:3; + u8 wup_ind_activation:1; + u8 reserved2[3]; } __packed; struct hif_mib_gl_set_multi_msg { - u8 enable_multi_tx_conf:1; - u8 reserved1:7; - u8 reserved2[3]; -} __packed; - -enum hif_cca_thr_mode { - HIF_CCA_THR_MODE_RELATIVE = 0x0, - HIF_CCA_THR_MODE_ABSOLUTE = 0x1 -}; - -struct hif_mib_gl_cca_config { - u8 cca_thr_mode; - u8 reserved[3]; -} __packed; - -#define MAX_NUMBER_DATA_FILTERS 0xA - -#define MAX_NUMBER_IPV4_ADDR_CONDITIONS 0x4 -#define MAX_NUMBER_IPV6_ADDR_CONDITIONS 0x4 -#define MAX_NUMBER_MAC_ADDR_CONDITIONS 0x4 -#define MAX_NUMBER_UC_MC_BC_CONDITIONS 0x4 -#define MAX_NUMBER_ETHER_TYPE_CONDITIONS 0x4 -#define MAX_NUMBER_PORT_CONDITIONS 0x4 -#define MAX_NUMBER_MAGIC_CONDITIONS 0x4 -#define MAX_NUMBER_ARP_CONDITIONS 0x2 -#define MAX_NUMBER_NS_CONDITIONS 0x2 - -struct hif_mib_ethertype_data_frame_condition { - u8 condition_idx; - u8 reserved; - u16 ether_type; -} __packed; - -enum hif_udp_tcp_protocol { - HIF_PROTOCOL_UDP = 0x0, - HIF_PROTOCOL_TCP = 0x1, - HIF_PROTOCOL_BOTH_UDP_TCP = 0x2 -}; - -enum hif_which_port { - HIF_PORT_DST = 0x0, - HIF_PORT_SRC = 0x1, - HIF_PORT_SRC_OR_DST = 0x2 -}; - -struct hif_mib_ports_data_frame_condition { - u8 condition_idx; - u8 protocol; - u8 which_port; - u8 reserved1; - u16 port_number; - u8 reserved2[2]; -} __packed; - -#define HIF_API_MAGIC_PATTERN_SIZE 32 - -struct hif_mib_magic_data_frame_condition { - u8 condition_idx; - u8 offset; - u8 magic_pattern_length; - u8 reserved; - u8 magic_pattern[HIF_API_MAGIC_PATTERN_SIZE]; + u8 enable_multi_tx_conf:1; + u8 reserved1:7; + u8 reserved2[3]; } __packed; enum hif_mac_addr_type { - HIF_MAC_ADDR_A1 = 0x0, - HIF_MAC_ADDR_A2 = 0x1, - HIF_MAC_ADDR_A3 = 0x2 + HIF_MAC_ADDR_A1 = 0x0, + HIF_MAC_ADDR_A2 = 0x1, + HIF_MAC_ADDR_A3 = 0x2 }; struct hif_mib_mac_addr_data_frame_condition { - u8 condition_idx; - u8 address_type; - u8 mac_address[ETH_ALEN]; -} __packed; - -enum hif_ip_addr_mode { - HIF_IP_ADDR_SRC = 0x0, - HIF_IP_ADDR_DST = 0x1 -}; - -struct hif_mib_ipv4_addr_data_frame_condition { - u8 condition_idx; - u8 address_mode; - u8 reserved[2]; - u8 i_pv4_address[HIF_API_IPV4_ADDRESS_SIZE]; -} __packed; - -struct hif_mib_ipv6_addr_data_frame_condition { - u8 condition_idx; - u8 address_mode; - u8 reserved[2]; - u8 i_pv6_address[HIF_API_IPV6_ADDRESS_SIZE]; + u8 condition_idx; + u8 address_type; + u8 mac_address[ETH_ALEN]; } __packed; #define HIF_FILTER_UNICAST 0x1 @@ -186,365 +99,289 @@ struct hif_mib_ipv6_addr_data_frame_condition { #define HIF_FILTER_BROADCAST 0x4 struct hif_mib_uc_mc_bc_data_frame_condition { - u8 condition_idx; - u8 allowed_frames; - u8 reserved[2]; + u8 condition_idx; + u8 allowed_frames; + u8 reserved[2]; } __packed; struct hif_mib_config_data_filter { - u8 filter_idx; - u8 enable; - u8 reserved1[2]; - u8 eth_type_cond; - u8 port_cond; - u8 magic_cond; - u8 mac_cond; - u8 ipv4_cond; - u8 ipv6_cond; - u8 uc_mc_bc_cond; - u8 reserved2; + u8 filter_idx; + u8 enable; + u8 reserved1[2]; + u8 eth_type_cond; + u8 port_cond; + u8 magic_cond; + u8 mac_cond; + u8 ipv4_cond; + u8 ipv6_cond; + u8 uc_mc_bc_cond; + u8 reserved2; } __packed; struct hif_mib_set_data_filtering { - u8 invert_matching:1; - u8 reserved1:7; - u8 enable:1; - u8 reserved2:7; - u8 reserved3[2]; + u8 invert_matching:1; + u8 reserved1:7; + u8 enable:1; + u8 reserved2:7; + u8 reserved3[2]; } __packed; enum hif_arp_ns_frame_treatment { - HIF_ARP_NS_FILTERING_DISABLE = 0x0, - HIF_ARP_NS_FILTERING_ENABLE = 0x1, - HIF_ARP_NS_REPLY_ENABLE = 0x2 + HIF_ARP_NS_FILTERING_DISABLE = 0x0, + HIF_ARP_NS_FILTERING_ENABLE = 0x1, + HIF_ARP_NS_REPLY_ENABLE = 0x2 }; struct hif_mib_arp_ip_addr_table { - u8 condition_idx; - u8 arp_enable; - u8 reserved[2]; - u8 ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; -} __packed; - -struct hif_mib_ns_ip_addr_table { - u8 condition_idx; - u8 ns_enable; - u8 reserved[2]; - u8 ipv6_address[HIF_API_IPV6_ADDRESS_SIZE]; + u8 condition_idx; + u8 arp_enable; + u8 reserved[2]; + u8 ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; } __packed; struct hif_mib_rx_filter { - u8 reserved1:1; - u8 bssid_filter:1; - u8 reserved2:1; - u8 fwd_probe_req:1; - u8 keep_alive_filter:1; - u8 reserved3:3; - u8 reserved4[3]; + u8 reserved1:1; + u8 bssid_filter:1; + u8 reserved2:1; + u8 fwd_probe_req:1; + u8 keep_alive_filter:1; + u8 reserved3:3; + u8 reserved4[3]; } __packed; -#define HIF_API_OUI_SIZE 3 -#define HIF_API_MATCH_DATA_SIZE 3 - struct hif_ie_table_entry { - u8 ie_id; - u8 has_changed:1; - u8 no_longer:1; - u8 has_appeared:1; - u8 reserved:1; - u8 num_match_data:4; - u8 oui[HIF_API_OUI_SIZE]; - u8 match_data[HIF_API_MATCH_DATA_SIZE]; + u8 ie_id; + u8 has_changed:1; + u8 no_longer:1; + u8 has_appeared:1; + u8 reserved:1; + u8 num_match_data:4; + u8 oui[3]; + u8 match_data[3]; } __packed; struct hif_mib_bcn_filter_table { - u32 num_of_info_elmts; + __le32 num_of_info_elmts; struct hif_ie_table_entry ie_table[]; } __packed; enum hif_beacon_filter { - HIF_BEACON_FILTER_DISABLE = 0x0, - HIF_BEACON_FILTER_ENABLE = 0x1, - HIF_BEACON_FILTER_AUTO_ERP = 0x2 + HIF_BEACON_FILTER_DISABLE = 0x0, + HIF_BEACON_FILTER_ENABLE = 0x1, + HIF_BEACON_FILTER_AUTO_ERP = 0x2 }; struct hif_mib_bcn_filter_enable { - u32 enable; - u32 bcn_count; -} __packed; - -struct hif_mib_group_seq_counter { - u32 bits4716; - u16 bits1500; - u16 reserved; -} __packed; - -struct hif_mib_tsf_counter { - u32 tsf_counterlo; - u32 tsf_counterhi; -} __packed; - -struct hif_mib_stats_table { - s16 latest_snr; - u8 latest_rcpi; - s8 latest_rssi; + __le32 enable; + __le32 bcn_count; } __packed; struct hif_mib_extended_count_table { - u32 count_plcp_errors; - u32 count_fcs_errors; - u32 count_tx_packets; - u32 count_rx_packets; - u32 count_rx_packet_errors; - u32 count_rx_decryption_failures; - u32 count_rx_mic_failures; - u32 count_rx_no_key_failures; - u32 count_tx_multicast_frames; - u32 count_tx_frames_success; - u32 count_tx_frame_failures; - u32 count_tx_frames_retried; - u32 count_tx_frames_multi_retried; - u32 count_rx_frame_duplicates; - u32 count_rts_success; - u32 count_rts_failures; - u32 count_ack_failures; - u32 count_rx_multicast_frames; - u32 count_rx_frames_success; - u32 count_rx_cmacicv_errors; - u32 count_rx_cmac_replays; - u32 count_rx_mgmt_ccmp_replays; - u32 count_rx_bipmic_errors; - u32 count_rx_beacon; - u32 count_miss_beacon; - u32 reserved[15]; + __le32 count_plcp_errors; + __le32 count_fcs_errors; + __le32 count_tx_packets; + __le32 count_rx_packets; + __le32 count_rx_packet_errors; + __le32 count_rx_decryption_failures; + __le32 count_rx_mic_failures; + __le32 count_rx_no_key_failures; + __le32 count_tx_multicast_frames; + __le32 count_tx_frames_success; + __le32 count_tx_frame_failures; + __le32 count_tx_frames_retried; + __le32 count_tx_frames_multi_retried; + __le32 count_rx_frame_duplicates; + __le32 count_rts_success; + __le32 count_rts_failures; + __le32 count_ack_failures; + __le32 count_rx_multicast_frames; + __le32 count_rx_frames_success; + __le32 count_rx_cmacicv_errors; + __le32 count_rx_cmac_replays; + __le32 count_rx_mgmt_ccmp_replays; + __le32 count_rx_bipmic_errors; + __le32 count_rx_beacon; + __le32 count_miss_beacon; + __le32 reserved[15]; } __packed; struct hif_mib_count_table { - u32 count_plcp_errors; - u32 count_fcs_errors; - u32 count_tx_packets; - u32 count_rx_packets; - u32 count_rx_packet_errors; - u32 count_rx_decryption_failures; - u32 count_rx_mic_failures; - u32 count_rx_no_key_failures; - u32 count_tx_multicast_frames; - u32 count_tx_frames_success; - u32 count_tx_frame_failures; - u32 count_tx_frames_retried; - u32 count_tx_frames_multi_retried; - u32 count_rx_frame_duplicates; - u32 count_rts_success; - u32 count_rts_failures; - u32 count_ack_failures; - u32 count_rx_multicast_frames; - u32 count_rx_frames_success; - u32 count_rx_cmacicv_errors; - u32 count_rx_cmac_replays; - u32 count_rx_mgmt_ccmp_replays; - u32 count_rx_bipmic_errors; -} __packed; - -struct hif_mib_max_tx_power_level { - s32 max_tx_power_level_rf_port1; - s32 max_tx_power_level_rf_port2; -} __packed; - -struct hif_mib_beacon_stats { - s32 latest_tbtt_diff; - u32 reserved[4]; + __le32 count_plcp_errors; + __le32 count_fcs_errors; + __le32 count_tx_packets; + __le32 count_rx_packets; + __le32 count_rx_packet_errors; + __le32 count_rx_decryption_failures; + __le32 count_rx_mic_failures; + __le32 count_rx_no_key_failures; + __le32 count_tx_multicast_frames; + __le32 count_tx_frames_success; + __le32 count_tx_frame_failures; + __le32 count_tx_frames_retried; + __le32 count_tx_frames_multi_retried; + __le32 count_rx_frame_duplicates; + __le32 count_rts_success; + __le32 count_rts_failures; + __le32 count_ack_failures; + __le32 count_rx_multicast_frames; + __le32 count_rx_frames_success; + __le32 count_rx_cmacicv_errors; + __le32 count_rx_cmac_replays; + __le32 count_rx_mgmt_ccmp_replays; + __le32 count_rx_bipmic_errors; } __packed; struct hif_mib_mac_address { - u8 mac_addr[ETH_ALEN]; - u16 reserved; -} __packed; - -struct hif_mib_dot11_max_transmit_msdu_lifetime { - u32 max_life_time; -} __packed; - -struct hif_mib_dot11_max_receive_lifetime { - u32 max_life_time; + u8 mac_addr[ETH_ALEN]; + __le16 reserved; } __packed; struct hif_mib_wep_default_key_id { - u8 wep_default_key_id; - u8 reserved[3]; + u8 wep_default_key_id; + u8 reserved[3]; } __packed; struct hif_mib_dot11_rts_threshold { - u32 threshold; + __le32 threshold; } __packed; struct hif_mib_slot_time { - u32 slot_time; + __le32 slot_time; } __packed; struct hif_mib_current_tx_power_level { - s32 power_level; + __le32 power_level; // signed value } __packed; struct hif_mib_non_erp_protection { - u8 use_cts_to_self:1; - u8 reserved1:7; - u8 reserved2[3]; + u8 use_cts_to_self:1; + u8 reserved1:7; + u8 reserved2[3]; } __packed; enum hif_tmplt { - HIF_TMPLT_PRBREQ = 0x0, - HIF_TMPLT_BCN = 0x1, - HIF_TMPLT_NULL = 0x2, - HIF_TMPLT_QOSNUL = 0x3, - HIF_TMPLT_PSPOLL = 0x4, - HIF_TMPLT_PRBRES = 0x5, - HIF_TMPLT_ARP = 0x6, - HIF_TMPLT_NA = 0x7 + HIF_TMPLT_PRBREQ = 0x0, + HIF_TMPLT_BCN = 0x1, + HIF_TMPLT_NULL = 0x2, + HIF_TMPLT_QOSNUL = 0x3, + HIF_TMPLT_PSPOLL = 0x4, + HIF_TMPLT_PRBRES = 0x5, + HIF_TMPLT_ARP = 0x6, + HIF_TMPLT_NA = 0x7 }; -#define HIF_API_MAX_TEMPLATE_FRAME_SIZE 700 +#define HIF_API_MAX_TEMPLATE_FRAME_SIZE 700 struct hif_mib_template_frame { - u8 frame_type; - u8 init_rate:7; - u8 mode:1; - u16 frame_length; - u8 frame[HIF_API_MAX_TEMPLATE_FRAME_SIZE]; + u8 frame_type; + u8 init_rate:7; + u8 mode:1; + __le16 frame_length; + u8 frame[]; } __packed; struct hif_mib_beacon_wake_up_period { - u8 wakeup_period_min; - u8 receive_dtim:1; - u8 reserved1:7; - u8 wakeup_period_max; - u8 reserved2; + u8 wakeup_period_min; + u8 receive_dtim:1; + u8 reserved1:7; + u8 wakeup_period_max; + u8 reserved2; } __packed; struct hif_mib_rcpi_rssi_threshold { - u8 detection:1; - u8 rcpi_rssi:1; - u8 upperthresh:1; - u8 lowerthresh:1; - u8 reserved:4; - u8 lower_threshold; - u8 upper_threshold; - u8 rolling_average_count; + u8 detection:1; + u8 rcpi_rssi:1; + u8 upperthresh:1; + u8 lowerthresh:1; + u8 reserved:4; + u8 lower_threshold; + u8 upper_threshold; + u8 rolling_average_count; } __packed; #define DEFAULT_BA_MAX_RX_BUFFER_SIZE 16 struct hif_mib_block_ack_policy { - u8 block_ack_tx_tid_policy; - u8 reserved1; - u8 block_ack_rx_tid_policy; - u8 block_ack_rx_max_buffer_size; -} __packed; - -struct hif_mib_override_int_rate { - u8 internal_tx_rate; - u8 non_erp_internal_tx_rate; - u8 reserved[2]; + u8 block_ack_tx_tid_policy; + u8 reserved1; + u8 block_ack_rx_tid_policy; + u8 block_ack_rx_max_buffer_size; } __packed; enum hif_mpdu_start_spacing { - HIF_MPDU_START_SPACING_NO_RESTRIC = 0x0, - HIF_MPDU_START_SPACING_QUARTER = 0x1, - HIF_MPDU_START_SPACING_HALF = 0x2, - HIF_MPDU_START_SPACING_ONE = 0x3, - HIF_MPDU_START_SPACING_TWO = 0x4, - HIF_MPDU_START_SPACING_FOUR = 0x5, - HIF_MPDU_START_SPACING_EIGHT = 0x6, - HIF_MPDU_START_SPACING_SIXTEEN = 0x7 + HIF_MPDU_START_SPACING_NO_RESTRIC = 0x0, + HIF_MPDU_START_SPACING_QUARTER = 0x1, + HIF_MPDU_START_SPACING_HALF = 0x2, + HIF_MPDU_START_SPACING_ONE = 0x3, + HIF_MPDU_START_SPACING_TWO = 0x4, + HIF_MPDU_START_SPACING_FOUR = 0x5, + HIF_MPDU_START_SPACING_EIGHT = 0x6, + HIF_MPDU_START_SPACING_SIXTEEN = 0x7 }; struct hif_mib_set_association_mode { - u8 preambtype_use:1; - u8 mode:1; - u8 rateset:1; - u8 spacing:1; - u8 reserved1:4; - u8 short_preamble:1; - u8 reserved2:7; - u8 greenfield:1; - u8 reserved3:7; - u8 mpdu_start_spacing; - u32 basic_rate_set; + u8 preambtype_use:1; + u8 mode:1; + u8 rateset:1; + u8 spacing:1; + u8 reserved1:4; + u8 short_preamble:1; + u8 reserved2:7; + u8 greenfield:1; + u8 reserved3:7; + u8 mpdu_start_spacing; + __le32 basic_rate_set; } __packed; struct hif_mib_set_uapsd_information { - u8 trig_bckgrnd:1; - u8 trig_be:1; - u8 trig_video:1; - u8 trig_voice:1; - u8 reserved1:4; - u8 deliv_bckgrnd:1; - u8 deliv_be:1; - u8 deliv_video:1; - u8 deliv_voice:1; - u8 reserved2:4; - u16 min_auto_trigger_interval; - u16 max_auto_trigger_interval; - u16 auto_trigger_step; + u8 trig_bckgrnd:1; + u8 trig_be:1; + u8 trig_video:1; + u8 trig_voice:1; + u8 reserved1:4; + u8 deliv_bckgrnd:1; + u8 deliv_be:1; + u8 deliv_video:1; + u8 deliv_voice:1; + u8 reserved2:4; + __le16 min_auto_trigger_interval; + __le16 max_auto_trigger_interval; + __le16 auto_trigger_step; } __packed; struct hif_mib_tx_rate_retry_policy { - u8 policy_index; - u8 short_retry_count; - u8 long_retry_count; - u8 first_rate_sel:2; - u8 terminate:1; - u8 count_init:1; - u8 reserved1:4; - u8 rate_recovery_count; - u8 reserved2[3]; - u8 rates[12]; + u8 policy_index; + u8 short_retry_count; + u8 long_retry_count; + u8 first_rate_sel:2; + u8 terminate:1; + u8 count_init:1; + u8 reserved1:4; + u8 rate_recovery_count; + u8 reserved2[3]; + u8 rates[12]; } __packed; -#define HIF_MIB_NUM_TX_RATE_RETRY_POLICIES 15 +#define HIF_TX_RETRY_POLICY_MAX 15 +#define HIF_TX_RETRY_POLICY_INVALID HIF_TX_RETRY_POLICY_MAX struct hif_mib_set_tx_rate_retry_policy { - u8 num_tx_rate_policies; - u8 reserved[3]; + u8 num_tx_rate_policies; + u8 reserved[3]; struct hif_mib_tx_rate_retry_policy tx_rate_retry_policy[]; } __packed; struct hif_mib_protected_mgmt_policy { - u8 pmf_enable:1; - u8 unpmf_allowed:1; - u8 host_enc_auth_frames:1; - u8 reserved1:5; - u8 reserved2[3]; -} __packed; - -struct hif_mib_set_ht_protection { - u8 dual_cts_prot:1; - u8 reserved1:7; - u8 reserved2[3]; + u8 pmf_enable:1; + u8 unpmf_allowed:1; + u8 host_enc_auth_frames:1; + u8 reserved1:5; + u8 reserved2[3]; } __packed; struct hif_mib_keep_alive_period { - u16 keep_alive_period; - u8 reserved[2]; -} __packed; - -struct hif_mib_arp_keep_alive_period { - u16 arp_keep_alive_period; - u8 encr_type; - u8 reserved; - u8 sender_ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; - u8 target_ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; -} __packed; - -struct hif_mib_inactivity_timer { - u8 min_active_time; - u8 max_active_time; - u16 reserved; -} __packed; - -struct hif_mib_interface_protection { - u8 use_cts_prot:1; - u8 reserved1:7; - u8 reserved2[3]; + __le16 keep_alive_period; + u8 reserved[2]; } __packed; #endif diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c index 33c22c5d629d..bb156033d1e1 100644 --- a/drivers/staging/wfx/hif_rx.c +++ b/drivers/staging/wfx/hif_rx.c @@ -22,9 +22,9 @@ static int hif_generic_confirm(struct wfx_dev *wdev, const struct hif_msg *hif, const void *buf) { // All confirm messages start with status - int status = le32_to_cpu(*((__le32 *) buf)); + int status = le32_to_cpup((__le32 *)buf); int cmd = hif->id; - int len = hif->len - 4; // drop header + int len = le16_to_cpu(hif->len) - 4; // drop header WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); @@ -100,10 +100,10 @@ static int hif_startup_indication(struct wfx_dev *wdev, return -EINVAL; } memcpy(&wdev->hw_caps, body, sizeof(struct hif_ind_startup)); - le32_to_cpus(&wdev->hw_caps.status); - le16_to_cpus(&wdev->hw_caps.hardware_id); - le16_to_cpus(&wdev->hw_caps.num_inp_ch_bufs); - le16_to_cpus(&wdev->hw_caps.size_inp_ch_buf); + le16_to_cpus((__le16 *)&wdev->hw_caps.hardware_id); + le16_to_cpus((__le16 *)&wdev->hw_caps.num_inp_ch_bufs); + le16_to_cpus((__le16 *)&wdev->hw_caps.size_inp_ch_buf); + le32_to_cpus((__le32 *)&wdev->hw_caps.supported_rate_mask); complete(&wdev->firmware_ready); return 0; @@ -127,7 +127,7 @@ static int hif_keys_indication(struct wfx_dev *wdev, u8 pubkey[API_NCP_PUB_KEY_SIZE]; // SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS is used by legacy secure link - if (body->status && body->status != SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS) + if (body->status && body->status != HIF_STATUS_SLK_NEGO_SUCCESS) dev_warn(wdev->dev, "secure link negociation error\n"); memcpy(pubkey, body->ncp_pub_key, sizeof(pubkey)); memreverse(pubkey, sizeof(pubkey)); @@ -158,26 +158,39 @@ static int hif_event_indication(struct wfx_dev *wdev, { struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); const struct hif_ind_event *body = buf; - struct wfx_hif_event *event; - int first; + int type = le32_to_cpu(body->event_id); + int cause; - WARN_ON(!wvif); - if (!wvif) + if (!wvif) { + dev_warn(wdev->dev, "received event for non-existent vif\n"); return 0; + } - event = kzalloc(sizeof(*event), GFP_KERNEL); - if (!event) - return -ENOMEM; - - memcpy(&event->evt, body, sizeof(struct hif_ind_event)); - spin_lock(&wvif->event_queue_lock); - first = list_empty(&wvif->event_queue); - list_add_tail(&event->link, &wvif->event_queue); - spin_unlock(&wvif->event_queue_lock); - - if (first) - schedule_work(&wvif->event_handler_work); - + switch (type) { + case HIF_EVENT_IND_RCPI_RSSI: + wfx_event_report_rssi(wvif, body->event_data.rcpi_rssi); + break; + case HIF_EVENT_IND_BSSLOST: + schedule_delayed_work(&wvif->beacon_loss_work, 0); + break; + case HIF_EVENT_IND_BSSREGAINED: + cancel_delayed_work(&wvif->beacon_loss_work); + dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n"); + break; + case HIF_EVENT_IND_PS_MODE_ERROR: + cause = le32_to_cpu(body->event_data.ps_mode_error); + dev_warn(wdev->dev, "error while processing power save request: %d\n", + cause); + if (cause == HIF_PS_ERROR_AP_NOT_RESP_TO_POLL) { + wvif->bss_not_support_ps_poll = true; + schedule_work(&wvif->update_pm_work); + } + break; + default: + dev_warn(wdev->dev, "unhandled event indication: %.2x\n", + type); + break; + } return 0; } @@ -224,53 +237,21 @@ static int hif_suspend_resume_indication(struct wfx_dev *wdev, struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); const struct hif_ind_suspend_resume_tx *body = buf; - WARN_ON(!wvif); - WARN(!body->suspend_resume_flags.bc_mc_only, "unsupported suspend/resume notification"); - if (body->suspend_resume_flags.resume) - wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE); - else - wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP); - - return 0; -} - -static int hif_error_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_error *body = buf; - u8 *pRollback = (u8 *) body->data; - u32 *pStatus = (u32 *) body->data; - - switch (body->type) { - case HIF_ERROR_FIRMWARE_ROLLBACK: - dev_err(wdev->dev, - "asynchronous error: firmware rollback error %d\n", - *pRollback); - break; - case HIF_ERROR_FIRMWARE_DEBUG_ENABLED: - dev_err(wdev->dev, "asynchronous error: firmware debug feature enabled\n"); - break; - case HIF_ERROR_OUTDATED_SESSION_KEY: - dev_err(wdev->dev, "asynchronous error: secure link outdated key: %#.8x\n", - *pStatus); - break; - case HIF_ERROR_INVALID_SESSION_KEY: - dev_err(wdev->dev, "asynchronous error: invalid session key\n"); - break; - case HIF_ERROR_OOR_VOLTAGE: - dev_err(wdev->dev, "asynchronous error: out-of-range overvoltage: %#.8x\n", - *pStatus); - break; - case HIF_ERROR_PDS_VERSION: - dev_err(wdev->dev, - "asynchronous error: wrong PDS payload or version: %#.8x\n", - *pStatus); - break; - default: - dev_err(wdev->dev, "asynchronous error: unknown (%d)\n", - body->type); - break; + if (body->suspend_resume_flags.bc_mc_only) { + WARN_ON(!wvif); + if (body->suspend_resume_flags.resume) + wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE); + else + wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP); + } else { + WARN(body->peer_sta_set, "misunderstood indication"); + WARN(hif->interface != 2, "misunderstood indication"); + if (body->suspend_resume_flags.resume) + wfx_suspend_hot_dev(wdev, STA_NOTIFY_AWAKE); + else + wfx_suspend_hot_dev(wdev, STA_NOTIFY_SLEEP); } + return 0; } @@ -278,13 +259,14 @@ static int hif_generic_indication(struct wfx_dev *wdev, const struct hif_msg *hif, const void *buf) { const struct hif_ind_generic *body = buf; + int type = le32_to_cpu(body->indication_type); - switch (body->indication_type) { + switch (type) { case HIF_GENERIC_INDICATION_TYPE_RAW: return 0; case HIF_GENERIC_INDICATION_TYPE_STRING: dev_info(wdev->dev, "firmware says: %s\n", - (char *) body->indication_data.raw_data); + (char *)body->indication_data.raw_data); return 0; case HIF_GENERIC_INDICATION_TYPE_RX_STATS: mutex_lock(&wdev->rx_stats_lock); @@ -296,22 +278,103 @@ static int hif_generic_indication(struct wfx_dev *wdev, sizeof(wdev->rx_stats)); mutex_unlock(&wdev->rx_stats_lock); return 0; + case HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO: + mutex_lock(&wdev->tx_power_loop_info_lock); + memcpy(&wdev->tx_power_loop_info, + &body->indication_data.tx_power_loop_info, + sizeof(wdev->tx_power_loop_info)); + mutex_unlock(&wdev->tx_power_loop_info_lock); + return 0; default: - dev_err(wdev->dev, - "generic_indication: unknown indication type: %#.8x\n", - body->indication_type); + dev_err(wdev->dev, "generic_indication: unknown indication type: %#.8x\n", + type); return -EIO; } } +static const struct { + int val; + const char *str; + bool has_param; +} hif_errors[] = { + { HIF_ERROR_FIRMWARE_ROLLBACK, + "rollback status" }, + { HIF_ERROR_FIRMWARE_DEBUG_ENABLED, + "debug feature enabled" }, + { HIF_ERROR_PDS_PAYLOAD, + "PDS version is not supported" }, + { HIF_ERROR_PDS_TESTFEATURE, + "PDS ask for an unknown test mode" }, + { HIF_ERROR_OOR_VOLTAGE, + "out-of-range power supply voltage", true }, + { HIF_ERROR_OOR_TEMPERATURE, + "out-of-range temperature", true }, + { HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE, + "secure link does not expect request during key exchange" }, + { HIF_ERROR_SLK_SESSION_KEY, + "secure link session key is invalid" }, + { HIF_ERROR_SLK_OVERFLOW, + "secure link overflow" }, + { HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE, + "secure link messages list does not match message encryption" }, + { HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW, + "bus clock is too slow (<1kHz)" }, + { HIF_ERROR_HIF_RX_DATA_TOO_LARGE, + "HIF message too large" }, + // Following errors only exists in old firmware versions: + { HIF_ERROR_HIF_TX_QUEUE_FULL, + "HIF messages queue is full" }, + { HIF_ERROR_HIF_BUS, + "HIF bus" }, + { HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED, + "secure link does not support multi-tx confirmations" }, + { HIF_ERROR_SLK_OUTDATED_SESSION_KEY, + "secure link session key is outdated" }, + { HIF_ERROR_SLK_DECRYPTION, + "secure link params (nonce or tag) mismatch" }, +}; + +static int hif_error_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + const struct hif_ind_error *body = buf; + int type = le32_to_cpu(body->type); + int param = (s8)body->data[0]; + int i; + + for (i = 0; i < ARRAY_SIZE(hif_errors); i++) + if (type == hif_errors[i].val) + break; + if (i < ARRAY_SIZE(hif_errors)) + if (hif_errors[i].has_param) + dev_err(wdev->dev, "asynchronous error: %s: %d\n", + hif_errors[i].str, param); + else + dev_err(wdev->dev, "asynchronous error: %s\n", + hif_errors[i].str); + else + dev_err(wdev->dev, "asynchronous error: unknown: %08x\n", type); + print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, + 16, 1, hif, le16_to_cpu(hif->len), false); + wdev->chip_frozen = true; + + return 0; +}; + static int hif_exception_indication(struct wfx_dev *wdev, const struct hif_msg *hif, const void *buf) { - size_t len = hif->len - 4; // drop header + const struct hif_ind_exception *body = buf; + int type = le32_to_cpu(body->type); - dev_err(wdev->dev, "firmware exception\n"); - print_hex_dump_bytes("Dump: ", DUMP_PREFIX_NONE, buf, len); - wdev->chip_frozen = 1; + if (type == 4) + dev_err(wdev->dev, "firmware assert %d\n", + le32_to_cpup((__le32 *)body->data)); + else + dev_err(wdev->dev, "firmware exception\n"); + print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, + 16, 1, hif, le16_to_cpu(hif->len), false); + wdev->chip_frozen = true; return -1; } diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c index 77bca43aca42..893b67f2f792 100644 --- a/drivers/staging/wfx/hif_tx.c +++ b/drivers/staging/wfx/hif_tx.c @@ -23,8 +23,8 @@ void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd) mutex_init(&hif_cmd->key_renew_lock); } -static void wfx_fill_header(struct hif_msg *hif, int if_id, unsigned int cmd, - size_t size) +static void wfx_fill_header(struct hif_msg *hif, int if_id, + unsigned int cmd, size_t size) { if (if_id == -1) if_id = 2; @@ -47,8 +47,8 @@ static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif) return NULL; } -int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, - size_t reply_len, bool async) +int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, + void *reply, size_t reply_len, bool async) { const char *mib_name = ""; const char *mib_sep = ""; @@ -82,6 +82,9 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, if (async) return 0; + if (wdev->poll_irq) + wfx_bh_poll_irq(wdev); + ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ); if (!ret) { dev_err(wdev->dev, "chip is abnormally long to answer\n"); @@ -91,7 +94,7 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, if (!ret) { dev_err(wdev->dev, "chip did not answer\n"); wfx_pending_dump_old_frames(wdev, 3000); - wdev->chip_frozen = 1; + wdev->chip_frozen = true; reinit_completion(&wdev->hif_cmd.done); ret = -ETIMEDOUT; } else { @@ -103,7 +106,7 @@ int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, if (ret && (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) { - mib_name = get_mib_name(((u16 *) request)[2]); + mib_name = get_mib_name(((u16 *)request)[2]); mib_sep = "/"; } if (ret < 0) @@ -128,7 +131,11 @@ int hif_shutdown(struct wfx_dev *wdev) int ret; struct hif_msg *hif; + if (wdev->chip_frozen) + return 0; wfx_alloc_hif(0, &hif); + if (!hif) + return -ENOMEM; wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0); ret = wfx_cmd_send(wdev, hif, NULL, 0, true); // After this command, chip won't reply. Be sure to give enough time to @@ -152,6 +159,8 @@ int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len) struct hif_msg *hif; struct hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif); + if (!hif) + return -ENOMEM; body->length = cpu_to_le16(len); memcpy(body->pds_data, conf, len); wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len); @@ -166,6 +175,8 @@ int hif_reset(struct wfx_vif *wvif, bool reset_stat) struct hif_msg *hif; struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif); + if (!hif) + return -ENOMEM; body->reset_flags.reset_stat = reset_stat; wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body)); ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); @@ -173,8 +184,8 @@ int hif_reset(struct wfx_vif *wvif, bool reset_stat) return ret; } -int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, - size_t val_len) +int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *val, size_t val_len) { int ret; struct hif_msg *hif; @@ -182,36 +193,43 @@ int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif); struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL); + if (!body || !reply) { + ret = -ENOMEM; + goto out; + } body->mib_id = cpu_to_le16(mib_id); wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body)); ret = wfx_cmd_send(wdev, hif, reply, buf_len, false); - if (!ret && mib_id != reply->mib_id) { - dev_warn(wdev->dev, - "%s: confirmation mismatch request\n", __func__); + if (!ret && mib_id != le16_to_cpu(reply->mib_id)) { + dev_warn(wdev->dev, "%s: confirmation mismatch request\n", + __func__); ret = -EIO; } if (ret == -ENOMEM) - dev_err(wdev->dev, - "buffer is too small to receive %s (%zu < %d)\n", - get_mib_name(mib_id), val_len, reply->length); + dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n", + get_mib_name(mib_id), val_len, + le16_to_cpu(reply->length)); if (!ret) - memcpy(val, &reply->mib_data, reply->length); + memcpy(val, &reply->mib_data, le16_to_cpu(reply->length)); else memset(val, 0xFF, val_len); +out: kfree(hif); kfree(reply); return ret; } -int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, - size_t val_len) +int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *val, size_t val_len) { int ret; struct hif_msg *hif; int buf_len = sizeof(struct hif_req_write_mib) + val_len; struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif); + if (!hif) + return -ENOMEM; body->mib_id = cpu_to_le16(mib_id); body->length = cpu_to_le16(val_len); memcpy(&body->mib_data, val, val_len); @@ -236,6 +254,8 @@ int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req, compiletime_assert(IEEE80211_MAX_SSID_LEN == HIF_API_SSID_SIZE, "API inconsistency"); + if (!hif) + return -ENOMEM; for (i = 0; i < req->n_ssids; i++) { memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid, IEEE80211_MAX_SSID_LEN); @@ -268,7 +288,7 @@ int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req, tmo_chan_bg = le32_to_cpu(body->max_channel_time) * USEC_PER_TU; tmo_chan_fg = 512 * USEC_PER_TU + body->probe_delay; tmo_chan_fg *= body->num_of_probe_requests; - tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg); + tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg) + 512 * USEC_PER_TU; wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len); ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); @@ -283,6 +303,8 @@ int hif_stop_scan(struct wfx_vif *wvif) // body associated to HIF_REQ_ID_STOP_SCAN is empty wfx_alloc_hif(0, &hif); + if (!hif) + return -ENOMEM; wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0); ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); kfree(hif); @@ -296,19 +318,24 @@ int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, struct hif_msg *hif; struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif); + WARN_ON(!conf->beacon_int); WARN_ON(!conf->basic_rates); + WARN_ON(sizeof(body->ssid) < ssidlen); + WARN(!conf->ibss_joined && !ssidlen, "joining an unknown BSS"); + if (!hif) + return -ENOMEM; body->infrastructure_bss_mode = !conf->ibss_joined; body->short_preamble = conf->use_short_preamble; if (channel && channel->flags & IEEE80211_CHAN_NO_IR) body->probe_for_join = 0; else body->probe_for_join = 1; - body->channel_number = cpu_to_le16(channel->hw_value); + body->channel_number = channel->hw_value; body->beacon_interval = cpu_to_le32(conf->beacon_int); body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); memcpy(body->bssid, conf->bssid, sizeof(body->bssid)); - if (!conf->ibss_joined && ssid) { + if (ssid) { body->ssid_length = cpu_to_le32(ssidlen); memcpy(body->ssid, ssid, ssidlen); } @@ -318,17 +345,17 @@ int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, return ret; } -int hif_set_bss_params(struct wfx_vif *wvif, - const struct hif_req_set_bss_params *arg) +int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count) { int ret; struct hif_msg *hif; - struct hif_req_set_bss_params *body = wfx_alloc_hif(sizeof(*body), - &hif); + struct hif_req_set_bss_params *body = + wfx_alloc_hif(sizeof(*body), &hif); - memcpy(body, arg, sizeof(*body)); - cpu_to_le16s(&body->aid); - cpu_to_le32s(&body->operational_rate_set); + if (!hif) + return -ENOMEM; + body->aid = cpu_to_le16(aid); + body->beacon_lost_count = beacon_lost_count; wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS, sizeof(*body)); ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); @@ -343,6 +370,8 @@ int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg) // FIXME: only send necessary bits struct hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif); + if (!hif) + return -ENOMEM; // FIXME: swap bytes as necessary in body memcpy(body, arg, sizeof(*body)); if (wfx_api_older_than(wdev, 1, 5)) @@ -363,6 +392,8 @@ int hif_remove_key(struct wfx_dev *wdev, int idx) struct hif_msg *hif; struct hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif); + if (!hif) + return -ENOMEM; body->entry_index = idx; wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body)); ret = wfx_cmd_send(wdev, hif, NULL, 0, false); @@ -382,6 +413,8 @@ int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, return -ENOMEM; WARN_ON(arg->aifs > 255); + if (!hif) + return -ENOMEM; body->aifsn = arg->aifs; body->cw_min = cpu_to_le16(arg->cw_min); body->cw_max = cpu_to_le16(arg->cw_max); @@ -408,6 +441,8 @@ int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout) if (!body) return -ENOMEM; + if (!hif) + return -ENOMEM; if (ps) { body->pm_mode.enter_psm = 1; // Firmware does not support more than 128ms @@ -428,9 +463,12 @@ int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, struct hif_msg *hif; struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif); + WARN_ON(!conf->beacon_int); + if (!hif) + return -ENOMEM; body->dtim_period = conf->dtim_period; body->short_preamble = conf->use_short_preamble; - body->channel_number = cpu_to_le16(channel->hw_value); + body->channel_number = channel->hw_value; body->beacon_interval = cpu_to_le32(conf->beacon_int); body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); @@ -449,6 +487,8 @@ int hif_beacon_transmit(struct wfx_vif *wvif, bool enable) struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body), &hif); + if (!hif) + return -ENOMEM; body->enable_beaconing = enable ? 1 : 0; wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT, sizeof(*body)); @@ -463,9 +503,11 @@ int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id) struct hif_msg *hif; struct hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif); + if (!hif) + return -ENOMEM; if (mac_addr) ether_addr_copy(body->mac_addr, mac_addr); - body->map_link_flags = *(struct hif_map_link_flags *) &flags; + body->map_link_flags = *(struct hif_map_link_flags *)&flags; body->peer_sta_id = sta_id; wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body)); ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); @@ -480,6 +522,8 @@ int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len) int buf_len = sizeof(struct hif_req_update_ie) + ies_len; struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif); + if (!hif) + return -ENOMEM; body->ie_flags.beacon = 1; body->num_ies = cpu_to_le16(1); memcpy(body->ie, ies, ies_len); @@ -489,14 +533,16 @@ int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len) return ret; } -int hif_sl_send_pub_keys(struct wfx_dev *wdev, const uint8_t *pubkey, - const uint8_t *pubkey_hmac) +int hif_sl_send_pub_keys(struct wfx_dev *wdev, + const u8 *pubkey, const u8 *pubkey_hmac) { int ret; struct hif_msg *hif; struct hif_req_sl_exchange_pub_keys *body = wfx_alloc_hif(sizeof(*body), &hif); + if (!hif) + return -ENOMEM; body->algorithm = HIF_SL_CURVE25519; memcpy(body->host_pub_key, pubkey, sizeof(body->host_pub_key)); memcpy(body->host_pub_key_mac, pubkey_hmac, @@ -506,7 +552,7 @@ int hif_sl_send_pub_keys(struct wfx_dev *wdev, const uint8_t *pubkey, ret = wfx_cmd_send(wdev, hif, NULL, 0, false); kfree(hif); // Compatibility with legacy secure link - if (ret == SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS) + if (ret == le32_to_cpu(HIF_STATUS_SLK_NEGO_SUCCESS)) ret = 0; return ret; } @@ -517,6 +563,8 @@ int hif_sl_config(struct wfx_dev *wdev, const unsigned long *bitmap) struct hif_msg *hif; struct hif_req_sl_configure *body = wfx_alloc_hif(sizeof(*body), &hif); + if (!hif) + return -ENOMEM; memcpy(body->encr_bmp, bitmap, sizeof(body->encr_bmp)); wfx_fill_header(hif, -1, HIF_REQ_ID_SL_CONFIGURE, sizeof(*body)); ret = wfx_cmd_send(wdev, hif, NULL, 0, false); @@ -524,21 +572,22 @@ int hif_sl_config(struct wfx_dev *wdev, const unsigned long *bitmap) return ret; } -int hif_sl_set_mac_key(struct wfx_dev *wdev, const u8 *slk_key, - int destination) +int hif_sl_set_mac_key(struct wfx_dev *wdev, const u8 *slk_key, int destination) { int ret; struct hif_msg *hif; struct hif_req_set_sl_mac_key *body = wfx_alloc_hif(sizeof(*body), &hif); + if (!hif) + return -ENOMEM; memcpy(body->key_value, slk_key, sizeof(body->key_value)); body->otp_or_ram = destination; wfx_fill_header(hif, -1, HIF_REQ_ID_SET_SL_MAC_KEY, sizeof(*body)); ret = wfx_cmd_send(wdev, hif, NULL, 0, false); kfree(hif); // Compatibility with legacy secure link - if (ret == SL_MAC_KEY_STATUS_SUCCESS) + if (ret == le32_to_cpu(HIF_STATUS_SLK_SET_KEY_SUCCESS)) ret = 0; return ret; } diff --git a/drivers/staging/wfx/hif_tx.h b/drivers/staging/wfx/hif_tx.h index f8520a14c14c..e9eca9330178 100644 --- a/drivers/staging/wfx/hif_tx.h +++ b/drivers/staging/wfx/hif_tx.h @@ -10,12 +10,11 @@ #ifndef WFX_HIF_TX_H #define WFX_HIF_TX_H -#include "hif_api_cmd.h" - struct ieee80211_channel; struct ieee80211_bss_conf; struct ieee80211_tx_queue_params; struct cfg80211_scan_request; +struct hif_req_add_key; struct wfx_dev; struct wfx_vif; @@ -48,8 +47,7 @@ int hif_stop_scan(struct wfx_vif *wvif); int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, struct ieee80211_channel *channel, const u8 *ssid, int ssidlen); int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout); -int hif_set_bss_params(struct wfx_vif *wvif, - const struct hif_req_set_bss_params *arg); +int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count); int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg); int hif_remove_key(struct wfx_dev *wdev, int idx); int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, @@ -59,8 +57,8 @@ int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, int hif_beacon_transmit(struct wfx_vif *wvif, bool enable); int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id); int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len); -int hif_sl_set_mac_key(struct wfx_dev *wdev, const u8 *slk_key, - int destination); +int hif_sl_set_mac_key(struct wfx_dev *wdev, + const u8 *slk_key, int destination); int hif_sl_config(struct wfx_dev *wdev, const unsigned long *bitmap); int hif_sl_send_pub_keys(struct wfx_dev *wdev, const u8 *pubkey, const u8 *pubkey_hmac); diff --git a/drivers/staging/wfx/hif_tx_mib.c b/drivers/staging/wfx/hif_tx_mib.c new file mode 100644 index 000000000000..1689cb42acc0 --- /dev/null +++ b/drivers/staging/wfx/hif_tx_mib.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ + +#include <linux/etherdevice.h> + +#include "wfx.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" +#include "hif_api_mib.h" + +int hif_set_output_power(struct wfx_vif *wvif, int val) +{ + struct hif_mib_current_tx_power_level arg = { + .power_level = cpu_to_le32(val * 10), + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_CURRENT_TX_POWER_LEVEL, + &arg, sizeof(arg)); +} + +int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, + unsigned int listen_interval) +{ + struct hif_mib_beacon_wake_up_period val = { + .wakeup_period_min = dtim_interval, + .receive_dtim = 0, + .wakeup_period_max = listen_interval, + }; + + if (dtim_interval > 0xFF || listen_interval > 0xFFFF) + return -EINVAL; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_WAKEUP_PERIOD, + &val, sizeof(val)); +} + +int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, + int rssi_thold, int rssi_hyst) +{ + struct hif_mib_rcpi_rssi_threshold arg = { + .rolling_average_count = 8, + .detection = 1, + }; + + if (!rssi_thold && !rssi_hyst) { + arg.upperthresh = 1; + arg.lowerthresh = 1; + } else { + arg.upper_threshold = rssi_thold + rssi_hyst; + arg.upper_threshold = (arg.upper_threshold + 110) * 2; + arg.lower_threshold = rssi_thold; + arg.lower_threshold = (arg.lower_threshold + 110) * 2; + } + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_RCPI_RSSI_THRESHOLD, &arg, sizeof(arg)); +} + +int hif_get_counters_table(struct wfx_dev *wdev, int vif_id, + struct hif_mib_extended_count_table *arg) +{ + if (wfx_api_older_than(wdev, 1, 3)) { + // extended_count_table is wider than count_table + memset(arg, 0xFF, sizeof(*arg)); + return hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE, + arg, sizeof(struct hif_mib_count_table)); + } else { + return hif_read_mib(wdev, vif_id, + HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, arg, + sizeof(struct hif_mib_extended_count_table)); + } +} + +int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac) +{ + struct hif_mib_mac_address msg = { }; + + if (mac) + ether_addr_copy(msg.mac_addr, mac); + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, + &msg, sizeof(msg)); +} + +int hif_set_rx_filter(struct wfx_vif *wvif, + bool filter_bssid, bool filter_prbreq) +{ + struct hif_mib_rx_filter val = { }; + + if (filter_bssid) + val.bssid_filter = 1; + if (!filter_prbreq) + val.fwd_probe_req = 1; + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, + &val, sizeof(val)); +} + +int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, + const struct hif_ie_table_entry *tbl) +{ + int ret; + struct hif_mib_bcn_filter_table *val; + int buf_len = struct_size(val, ie_table, tbl_len); + + val = kzalloc(buf_len, GFP_KERNEL); + if (!val) + return -ENOMEM; + val->num_of_info_elmts = cpu_to_le32(tbl_len); + memcpy(val->ie_table, tbl, tbl_len * sizeof(*tbl)); + ret = hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_FILTER_TABLE, val, buf_len); + kfree(val); + return ret; +} + +int hif_beacon_filter_control(struct wfx_vif *wvif, + int enable, int beacon_count) +{ + struct hif_mib_bcn_filter_enable arg = { + .enable = cpu_to_le32(enable), + .bcn_count = cpu_to_le32(beacon_count), + }; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_FILTER_ENABLE, + &arg, sizeof(arg)); +} + +int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode) +{ + struct hif_mib_gl_operational_power_mode val = { + .power_mode = mode, + .wup_ind_activation = 1, + }; + + return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE, + &val, sizeof(val)); +} + +int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, + u8 frame_type, int init_rate) +{ + struct hif_mib_template_frame *arg; + + WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big"); + skb_push(skb, 4); + arg = (struct hif_mib_template_frame *)skb->data; + skb_pull(skb, 4); + arg->init_rate = init_rate; + arg->frame_type = frame_type; + arg->frame_length = cpu_to_le16(skb->len); + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME, + arg, sizeof(*arg) + skb->len); +} + +int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required) +{ + struct hif_mib_protected_mgmt_policy val = { }; + + WARN(required && !capable, "incoherent arguments"); + if (capable) { + val.pmf_enable = 1; + val.host_enc_auth_frames = 1; + } + if (!required) + val.unpmf_allowed = 1; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_PROTECTED_MGMT_POLICY, + &val, sizeof(val)); +} + +int hif_set_block_ack_policy(struct wfx_vif *wvif, + u8 tx_tid_policy, u8 rx_tid_policy) +{ + struct hif_mib_block_ack_policy val = { + .block_ack_tx_tid_policy = tx_tid_policy, + .block_ack_rx_tid_policy = rx_tid_policy, + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY, + &val, sizeof(val)); +} + +int hif_set_association_mode(struct wfx_vif *wvif, + struct ieee80211_bss_conf *info) +{ + struct ieee80211_sta *sta = NULL; + struct hif_mib_set_association_mode val = { + .preambtype_use = 1, + .mode = 1, + .spacing = 1, + .short_preamble = info->use_short_preamble, + }; + + rcu_read_lock(); // protect sta + if (info->bssid && !info->ibss_joined) + sta = ieee80211_find_sta(wvif->vif, info->bssid); + + // FIXME: it is strange to not retrieve all information from bss_info + if (sta && sta->ht_cap.ht_supported) { + val.mpdu_start_spacing = sta->ht_cap.ampdu_density; + if (!(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)) + val.greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); + } + rcu_read_unlock(); + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_ASSOCIATION_MODE, &val, sizeof(val)); +} + +int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, + int policy_index, u8 *rates) +{ + struct hif_mib_set_tx_rate_retry_policy *arg; + size_t size = struct_size(arg, tx_rate_retry_policy, 1); + int ret; + + arg = kzalloc(size, GFP_KERNEL); + if (!arg) + return -ENOMEM; + arg->num_tx_rate_policies = 1; + arg->tx_rate_retry_policy[0].policy_index = policy_index; + arg->tx_rate_retry_policy[0].short_retry_count = 255; + arg->tx_rate_retry_policy[0].long_retry_count = 255; + arg->tx_rate_retry_policy[0].first_rate_sel = 1; + arg->tx_rate_retry_policy[0].terminate = 1; + arg->tx_rate_retry_policy[0].count_init = 1; + memcpy(&arg->tx_rate_retry_policy[0].rates, rates, + sizeof(arg->tx_rate_retry_policy[0].rates)); + ret = hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size); + kfree(arg); + return ret; +} + +int hif_set_mac_addr_condition(struct wfx_vif *wvif, + int idx, const u8 *mac_addr) +{ + struct hif_mib_mac_addr_data_frame_condition val = { + .condition_idx = idx, + .address_type = HIF_MAC_ADDR_A1, + }; + + ether_addr_copy(val.mac_address, mac_addr); + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION, + &val, sizeof(val)); +} + +int hif_set_uc_mc_bc_condition(struct wfx_vif *wvif, int idx, u8 allowed_frames) +{ + struct hif_mib_uc_mc_bc_data_frame_condition val = { + .condition_idx = idx, + .allowed_frames = allowed_frames, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION, + &val, sizeof(val)); +} + +int hif_set_config_data_filter(struct wfx_vif *wvif, bool enable, int idx, + int mac_filters, int frames_types_filters) +{ + struct hif_mib_config_data_filter val = { + .enable = enable, + .filter_idx = idx, + .mac_cond = mac_filters, + .uc_mc_bc_cond = frames_types_filters, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_CONFIG_DATA_FILTER, &val, sizeof(val)); +} + +int hif_set_data_filtering(struct wfx_vif *wvif, bool enable, bool invert) +{ + struct hif_mib_set_data_filtering val = { + .enable = enable, + .invert_matching = invert, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_DATA_FILTERING, &val, sizeof(val)); +} + +int hif_keep_alive_period(struct wfx_vif *wvif, int period) +{ + struct hif_mib_keep_alive_period arg = { + .keep_alive_period = cpu_to_le16(period), + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD, + &arg, sizeof(arg)); +}; + +int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr) +{ + struct hif_mib_arp_ip_addr_table arg = { + .condition_idx = idx, + .arp_enable = HIF_ARP_NS_FILTERING_DISABLE, + }; + + if (addr) { + // Caution: type of addr is __be32 + memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address)); + arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE; + } + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE, + &arg, sizeof(arg)); +} + +int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable) +{ + struct hif_mib_gl_set_multi_msg arg = { + .enable_multi_tx_conf = enable, + }; + + return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, + &arg, sizeof(arg)); +} + +int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val) +{ + struct hif_mib_set_uapsd_information arg = { }; + + if (val & BIT(IEEE80211_AC_VO)) + arg.trig_voice = 1; + if (val & BIT(IEEE80211_AC_VI)) + arg.trig_video = 1; + if (val & BIT(IEEE80211_AC_BE)) + arg.trig_be = 1; + if (val & BIT(IEEE80211_AC_BK)) + arg.trig_bckgrnd = 1; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_UAPSD_INFORMATION, + &arg, sizeof(arg)); +} + +int hif_erp_use_protection(struct wfx_vif *wvif, bool enable) +{ + struct hif_mib_non_erp_protection arg = { + .use_cts_to_self = enable, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg)); +} + +int hif_slot_time(struct wfx_vif *wvif, int val) +{ + struct hif_mib_slot_time arg = { + .slot_time = cpu_to_le32(val), + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, + &arg, sizeof(arg)); +} + +int hif_wep_default_key_id(struct wfx_vif *wvif, int val) +{ + struct hif_mib_wep_default_key_id arg = { + .wep_default_key_id = val, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, + &arg, sizeof(arg)); +} + +int hif_rts_threshold(struct wfx_vif *wvif, int val) +{ + struct hif_mib_dot11_rts_threshold arg = { + .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF), + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg)); +} diff --git a/drivers/staging/wfx/hif_tx_mib.h b/drivers/staging/wfx/hif_tx_mib.h index 26b1406f9f6c..86683de7de7c 100644 --- a/drivers/staging/wfx/hif_tx_mib.h +++ b/drivers/staging/wfx/hif_tx_mib.h @@ -9,398 +9,48 @@ #ifndef WFX_HIF_TX_MIB_H #define WFX_HIF_TX_MIB_H -#include <linux/etherdevice.h> - -#include "wfx.h" -#include "hif_tx.h" -#include "hif_api_mib.h" - -static inline int hif_set_output_power(struct wfx_vif *wvif, int val) -{ - struct hif_mib_current_tx_power_level arg = { - .power_level = cpu_to_le32(val * 10), - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_CURRENT_TX_POWER_LEVEL, - &arg, sizeof(arg)); -} - -static inline int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, - unsigned int dtim_interval, - unsigned int listen_interval) -{ - struct hif_mib_beacon_wake_up_period val = { - .wakeup_period_min = dtim_interval, - .receive_dtim = 0, - .wakeup_period_max = cpu_to_le16(listen_interval), - }; - - if (dtim_interval > 0xFF || listen_interval > 0xFFFF) - return -EINVAL; - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_BEACON_WAKEUP_PERIOD, - &val, sizeof(val)); -} - -static inline int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, - int rssi_thold, int rssi_hyst) -{ - struct hif_mib_rcpi_rssi_threshold arg = { - .rolling_average_count = 8, - .detection = 1, - }; - - if (!rssi_thold && !rssi_hyst) { - arg.upperthresh = 1; - arg.lowerthresh = 1; - } else { - arg.upper_threshold = rssi_thold + rssi_hyst; - arg.upper_threshold = (arg.upper_threshold + 110) * 2; - arg.lower_threshold = rssi_thold; - arg.lower_threshold = (arg.lower_threshold + 110) * 2; - } - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_RCPI_RSSI_THRESHOLD, &arg, sizeof(arg)); -} - -static inline int hif_get_counters_table(struct wfx_dev *wdev, - struct hif_mib_extended_count_table *arg) -{ - if (wfx_api_older_than(wdev, 1, 3)) { - // extended_count_table is wider than count_table - memset(arg, 0xFF, sizeof(*arg)); - return hif_read_mib(wdev, 0, HIF_MIB_ID_COUNTERS_TABLE, - arg, sizeof(struct hif_mib_count_table)); - } else { - return hif_read_mib(wdev, 0, - HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, arg, - sizeof(struct hif_mib_extended_count_table)); - } -} - -static inline int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac) -{ - struct hif_mib_mac_address msg = { }; - - if (mac) - ether_addr_copy(msg.mac_addr, mac); - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, - &msg, sizeof(msg)); -} - -static inline int hif_set_rx_filter(struct wfx_vif *wvif, bool filter_bssid, - bool fwd_probe_req) -{ - struct hif_mib_rx_filter val = { }; - - if (filter_bssid) - val.bssid_filter = 1; - if (fwd_probe_req) - val.fwd_probe_req = 1; - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, - &val, sizeof(val)); -} - -static inline int hif_set_beacon_filter_table(struct wfx_vif *wvif, - int tbl_len, - struct hif_ie_table_entry *tbl) -{ - int ret; - struct hif_mib_bcn_filter_table *val; - int buf_len = struct_size(val, ie_table, tbl_len); - - val = kzalloc(buf_len, GFP_KERNEL); - if (!val) - return -ENOMEM; - val->num_of_info_elmts = cpu_to_le32(tbl_len); - memcpy(val->ie_table, tbl, tbl_len * sizeof(*tbl)); - ret = hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_BEACON_FILTER_TABLE, val, buf_len); - kfree(val); - return ret; -} - -static inline int hif_beacon_filter_control(struct wfx_vif *wvif, - int enable, int beacon_count) -{ - struct hif_mib_bcn_filter_enable arg = { - .enable = cpu_to_le32(enable), - .bcn_count = cpu_to_le32(beacon_count), - }; - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_BEACON_FILTER_ENABLE, - &arg, sizeof(arg)); -} - -static inline int hif_set_operational_mode(struct wfx_dev *wdev, - enum hif_op_power_mode mode) -{ - struct hif_mib_gl_operational_power_mode val = { - .power_mode = mode, - .wup_ind_activation = 1, - }; - - return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE, - &val, sizeof(val)); -} - -static inline int hif_set_template_frame(struct wfx_vif *wvif, - struct sk_buff *skb, - u8 frame_type, int init_rate) -{ - struct hif_mib_template_frame *arg; - - skb_push(skb, 4); - arg = (struct hif_mib_template_frame *)skb->data; - skb_pull(skb, 4); - arg->init_rate = init_rate; - arg->frame_type = frame_type; - arg->frame_length = cpu_to_le16(skb->len); - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME, - arg, sizeof(*arg)); -} - -static inline int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required) -{ - struct hif_mib_protected_mgmt_policy val = { }; - - WARN(required && !capable, "incoherent arguments"); - if (capable) { - val.pmf_enable = 1; - val.host_enc_auth_frames = 1; - } - if (!required) - val.unpmf_allowed = 1; - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_PROTECTED_MGMT_POLICY, - &val, sizeof(val)); -} - -static inline int hif_set_block_ack_policy(struct wfx_vif *wvif, - u8 tx_tid_policy, u8 rx_tid_policy) -{ - struct hif_mib_block_ack_policy val = { - .block_ack_tx_tid_policy = tx_tid_policy, - .block_ack_rx_tid_policy = rx_tid_policy, - }; - - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY, - &val, sizeof(val)); -} - -static inline int hif_set_association_mode(struct wfx_vif *wvif, - struct ieee80211_bss_conf *info) -{ - int basic_rates = wfx_rate_mask_to_hw(wvif->wdev, info->basic_rates); - struct ieee80211_sta *sta = NULL; - struct hif_mib_set_association_mode val = { - .preambtype_use = 1, - .mode = 1, - .rateset = 1, - .spacing = 1, - .short_preamble = info->use_short_preamble, - .basic_rate_set = cpu_to_le32(basic_rates) - }; - - rcu_read_lock(); // protect sta - if (info->bssid && !info->ibss_joined) - sta = ieee80211_find_sta(wvif->vif, info->bssid); - - // FIXME: it is strange to not retrieve all information from bss_info - if (sta && sta->ht_cap.ht_supported) { - val.mpdu_start_spacing = sta->ht_cap.ampdu_density; - if (!(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)) - val.greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); - } - rcu_read_unlock(); - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_SET_ASSOCIATION_MODE, &val, sizeof(val)); -} - -static inline int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, - int policy_index, uint8_t *rates) -{ - struct hif_mib_set_tx_rate_retry_policy *arg; - size_t size = struct_size(arg, tx_rate_retry_policy, 1); - int ret; - - arg = kzalloc(size, GFP_KERNEL); - arg->num_tx_rate_policies = 1; - arg->tx_rate_retry_policy[0].policy_index = policy_index; - arg->tx_rate_retry_policy[0].short_retry_count = 255; - arg->tx_rate_retry_policy[0].long_retry_count = 255; - arg->tx_rate_retry_policy[0].first_rate_sel = 1; - arg->tx_rate_retry_policy[0].terminate = 1; - arg->tx_rate_retry_policy[0].count_init = 1; - memcpy(&arg->tx_rate_retry_policy[0].rates, rates, - sizeof(arg->tx_rate_retry_policy[0].rates)); - ret = hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size); - kfree(arg); - return ret; -} - -static inline int hif_set_mac_addr_condition(struct wfx_vif *wvif, - int idx, const u8 *mac_addr) -{ - struct hif_mib_mac_addr_data_frame_condition val = { - .condition_idx = idx, - .address_type = HIF_MAC_ADDR_A1, - }; - - ether_addr_copy(val.mac_address, mac_addr); - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION, - &val, sizeof(val)); -} - -static inline int hif_set_uc_mc_bc_condition(struct wfx_vif *wvif, - int idx, u8 allowed_frames) -{ - struct hif_mib_uc_mc_bc_data_frame_condition val = { - .condition_idx = idx, - .allowed_frames = allowed_frames, - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION, - &val, sizeof(val)); -} - -static inline int hif_set_config_data_filter(struct wfx_vif *wvif, bool enable, - int idx, int mac_filters, - int frames_types_filters) -{ - struct hif_mib_config_data_filter val = { - .enable = enable, - .filter_idx = idx, - .mac_cond = mac_filters, - .uc_mc_bc_cond = frames_types_filters, - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_CONFIG_DATA_FILTER, &val, sizeof(val)); -} - -static inline int hif_set_data_filtering(struct wfx_vif *wvif, - bool enable, bool invert) -{ - struct hif_mib_set_data_filtering val = { - .enable = enable, - .invert_matching = invert, - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_SET_DATA_FILTERING, &val, sizeof(val)); -} - -static inline int hif_keep_alive_period(struct wfx_vif *wvif, int period) -{ - struct hif_mib_keep_alive_period arg = { - .keep_alive_period = cpu_to_le16(period), - }; - - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD, - &arg, sizeof(arg)); -}; - -static inline int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, - __be32 *addr) -{ - struct hif_mib_arp_ip_addr_table arg = { - .condition_idx = idx, - .arp_enable = HIF_ARP_NS_FILTERING_DISABLE, - }; - - if (addr) { - // Caution: type of addr is __be32 - memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address)); - arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE; - } - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE, - &arg, sizeof(arg)); -} - -static inline int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable) -{ - struct hif_mib_gl_set_multi_msg arg = { - .enable_multi_tx_conf = enable, - }; - - return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, - &arg, sizeof(arg)); -} - -static inline int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val) -{ - struct hif_mib_set_uapsd_information arg = { }; - - if (val & BIT(IEEE80211_AC_VO)) - arg.trig_voice = 1; - if (val & BIT(IEEE80211_AC_VI)) - arg.trig_video = 1; - if (val & BIT(IEEE80211_AC_BE)) - arg.trig_be = 1; - if (val & BIT(IEEE80211_AC_BK)) - arg.trig_bckgrnd = 1; - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_SET_UAPSD_INFORMATION, - &arg, sizeof(arg)); -} - -static inline int hif_erp_use_protection(struct wfx_vif *wvif, bool enable) -{ - struct hif_mib_non_erp_protection arg = { - .use_cts_to_self = enable, - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg)); -} - -static inline int hif_slot_time(struct wfx_vif *wvif, int val) -{ - struct hif_mib_slot_time arg = { - .slot_time = cpu_to_le32(val), - }; - - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, - &arg, sizeof(arg)); -} - -static inline int hif_dual_cts_protection(struct wfx_vif *wvif, bool enable) -{ - struct hif_mib_set_ht_protection arg = { - .dual_cts_prot = enable, - }; - - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_HT_PROTECTION, - &arg, sizeof(arg)); -} - -static inline int hif_wep_default_key_id(struct wfx_vif *wvif, int val) -{ - struct hif_mib_wep_default_key_id arg = { - .wep_default_key_id = val, - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, - &arg, sizeof(arg)); -} - -static inline int hif_rts_threshold(struct wfx_vif *wvif, int val) -{ - struct hif_mib_dot11_rts_threshold arg = { - .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF), - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg)); -} +struct wfx_vif; +struct sk_buff; + +int hif_set_output_power(struct wfx_vif *wvif, int val); +int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, + unsigned int listen_interval); +int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, + int rssi_thold, int rssi_hyst); +int hif_get_counters_table(struct wfx_dev *wdev, int vif_id, + struct hif_mib_extended_count_table *arg); +int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac); +int hif_set_rx_filter(struct wfx_vif *wvif, + bool filter_bssid, bool fwd_probe_req); +int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, + const struct hif_ie_table_entry *tbl); +int hif_beacon_filter_control(struct wfx_vif *wvif, + int enable, int beacon_count); +int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode); +int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, + u8 frame_type, int init_rate); +int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required); +int hif_set_block_ack_policy(struct wfx_vif *wvif, + u8 tx_tid_policy, u8 rx_tid_policy); +int hif_set_association_mode(struct wfx_vif *wvif, + struct ieee80211_bss_conf *info); +int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, + int policy_index, u8 *rates); +int hif_set_mac_addr_condition(struct wfx_vif *wvif, + int idx, const u8 *mac_addr); +int hif_set_uc_mc_bc_condition(struct wfx_vif *wvif, + int idx, u8 allowed_frames); +int hif_set_config_data_filter(struct wfx_vif *wvif, bool enable, int idx, + int mac_filters, int frames_types_filters); +int hif_set_data_filtering(struct wfx_vif *wvif, bool enable, bool invert); +int hif_keep_alive_period(struct wfx_vif *wvif, int period); +int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr); +int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable); +int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val); +int hif_erp_use_protection(struct wfx_vif *wvif, bool enable); +int hif_slot_time(struct wfx_vif *wvif, int val); +int hif_wep_default_key_id(struct wfx_vif *wvif, int val); +int hif_rts_threshold(struct wfx_vif *wvif, int val); #endif diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c index d3a141d95a0e..777217cdf9a7 100644 --- a/drivers/staging/wfx/hwio.c +++ b/drivers/staging/wfx/hwio.c @@ -106,8 +106,8 @@ err: return ret; } -static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, - size_t len) +static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, + void *buf, size_t len) { int ret; int i; @@ -195,8 +195,8 @@ static int indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr, return ret; } -static int indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr, - u32 *val) +static int indirect_read32_locked(struct wfx_dev *wdev, int reg, + u32 addr, u32 *val) { int ret; __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); @@ -205,15 +205,15 @@ static int indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr, return -ENOMEM; wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32)); - *val = cpu_to_le32(*tmp); + *val = le32_to_cpu(*tmp); _trace_io_ind_read32(reg, addr, *val); wdev->hwbus_ops->unlock(wdev->hwbus_priv); kfree(tmp); return ret; } -static int indirect_write32_locked(struct wfx_dev *wdev, int reg, u32 addr, - u32 val) +static int indirect_write32_locked(struct wfx_dev *wdev, int reg, + u32 addr, u32 val) { int ret; __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); @@ -233,7 +233,7 @@ int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len) { int ret; - WARN((long) buf & 3, "%s: unaligned buffer", __func__); + WARN((long)buf & 3, "%s: unaligned buffer", __func__); wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len); @@ -249,7 +249,7 @@ int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len) { int ret; - WARN((long) buf & 3, "%s: unaligned buffer", __func__); + WARN((long)buf & 3, "%s: unaligned buffer", __func__); wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len); diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c index 96adfa330604..5ee2ffc5f935 100644 --- a/drivers/staging/wfx/key.c +++ b/drivers/staging/wfx/key.c @@ -5,6 +5,7 @@ * Copyright (c) 2017-2019, Silicon Laboratories, Inc. * Copyright (c) 2010, ST-Ericsson */ +#include <linux/etherdevice.h> #include <net/mac80211.h> #include "key.h" @@ -20,14 +21,12 @@ static int wfx_alloc_key(struct wfx_dev *wdev) return -1; wdev->key_map |= BIT(idx); - wdev->keys[idx].entry_index = idx; return idx; } static void wfx_free_key(struct wfx_dev *wdev, int idx) { WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation"); - memset(&wdev->keys[idx], 0, sizeof(wdev->keys[idx])); wdev->key_map &= ~BIT(idx); } @@ -159,7 +158,7 @@ static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { int ret; - struct hif_req_add_key *k; + struct hif_req_add_key k = { }; struct ieee80211_key_seq seq; struct wfx_dev *wdev = wvif->wdev; int idx = wfx_alloc_key(wvif->wdev); @@ -169,44 +168,44 @@ static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, ieee80211_get_key_rx_seq(key, 0, &seq); if (idx < 0) return -EINVAL; - k = &wdev->keys[idx]; - k->int_id = wvif->id; + k.int_id = wvif->id; + k.entry_index = idx; if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || key->cipher == WLAN_CIPHER_SUITE_WEP104) { if (pairwise) - k->type = fill_wep_pair(&k->key.wep_pairwise_key, key, - sta->addr); + k.type = fill_wep_pair(&k.key.wep_pairwise_key, key, + sta->addr); else - k->type = fill_wep_group(&k->key.wep_group_key, key); + k.type = fill_wep_group(&k.key.wep_group_key, key); } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { if (pairwise) - k->type = fill_tkip_pair(&k->key.tkip_pairwise_key, key, - sta->addr); + k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key, + sta->addr); else - k->type = fill_tkip_group(&k->key.tkip_group_key, key, - &seq, wvif->vif->type); + k.type = fill_tkip_group(&k.key.tkip_group_key, key, + &seq, wvif->vif->type); } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) { if (pairwise) - k->type = fill_ccmp_pair(&k->key.aes_pairwise_key, key, - sta->addr); + k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key, + sta->addr); else - k->type = fill_ccmp_group(&k->key.aes_group_key, key, - &seq); + k.type = fill_ccmp_group(&k.key.aes_group_key, key, + &seq); } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) { if (pairwise) - k->type = fill_sms4_pair(&k->key.wapi_pairwise_key, key, - sta->addr); + k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key, + sta->addr); else - k->type = fill_sms4_group(&k->key.wapi_group_key, key); + k.type = fill_sms4_group(&k.key.wapi_group_key, key); } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { - k->type = fill_aes_cmac_group(&k->key.igtk_group_key, key, - &seq); + k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, + &seq); } else { dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher); wfx_free_key(wdev, idx); return -EOPNOTSUPP; } - ret = hif_add_key(wdev, k); + ret = hif_add_key(wdev, &k); if (ret) { wfx_free_key(wdev, idx); return -EOPNOTSUPP; @@ -229,7 +228,7 @@ int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { int ret = -EOPNOTSUPP; - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; mutex_lock(&wvif->wdev->conf_mutex); if (cmd == SET_KEY) @@ -240,29 +239,3 @@ int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -int wfx_upload_keys(struct wfx_vif *wvif) -{ - int i; - struct hif_req_add_key *key; - struct wfx_dev *wdev = wvif->wdev; - - for (i = 0; i < ARRAY_SIZE(wdev->keys); i++) { - if (wdev->key_map & BIT(i)) { - key = &wdev->keys[i]; - if (key->int_id == wvif->id) - hif_add_key(wdev, key); - } - } - return 0; -} - -void wfx_wep_key_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(work, struct wfx_vif, wep_key_work); - - wfx_tx_flush(wvif->wdev); - hif_wep_default_key_id(wvif, wvif->wep_default_key_id); - wfx_pending_requeue(wvif->wdev, wvif->wep_pending_skb); - wvif->wep_pending_skb = NULL; - wfx_tx_unlock(wvif->wdev); -} diff --git a/drivers/staging/wfx/key.h b/drivers/staging/wfx/key.h index 9436ccdf4d3b..ff31fc9c565a 100644 --- a/drivers/staging/wfx/key.h +++ b/drivers/staging/wfx/key.h @@ -16,7 +16,5 @@ struct wfx_vif; int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); -int wfx_upload_keys(struct wfx_vif *wvif); -void wfx_wep_key_work(struct work_struct *work); #endif /* WFX_STA_H */ diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c index 3c4c240229ad..6bd96f476388 100644 --- a/drivers/staging/wfx/main.c +++ b/drivers/staging/wfx/main.c @@ -28,6 +28,7 @@ #include "bh.h" #include "sta.h" #include "key.h" +#include "scan.h" #include "debug.h" #include "data_tx.h" #include "secure_link.h" @@ -106,7 +107,7 @@ static const struct ieee80211_supported_band wfx_band_2ghz = { .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, .mcs = { .rx_mask = { 0xFF }, // MCS0 to MCS7 - .rx_highest = 65, + .rx_highest = cpu_to_le16(72), .tx_params = IEEE80211_HT_MCS_TX_DEFINED, }, }, @@ -133,15 +134,19 @@ static const struct ieee80211_ops wfx_ops = { .remove_interface = wfx_remove_interface, .config = wfx_config, .tx = wfx_tx, + .join_ibss = wfx_join_ibss, + .leave_ibss = wfx_leave_ibss, .conf_tx = wfx_conf_tx, .hw_scan = wfx_hw_scan, .cancel_hw_scan = wfx_cancel_hw_scan, + .start_ap = wfx_start_ap, + .stop_ap = wfx_stop_ap, .sta_add = wfx_sta_add, .sta_remove = wfx_sta_remove, - .sta_notify = wfx_sta_notify, .set_tim = wfx_set_tim, .set_key = wfx_set_key, .set_rts_threshold = wfx_set_rts_threshold, + .set_default_unicast_key = wfx_set_default_unicast_key, .bss_info_changed = wfx_bss_info_changed, .prepare_multicast = wfx_prepare_multicast, .configure_filter = wfx_configure_filter, @@ -165,8 +170,8 @@ bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor) return false; } -struct gpio_desc *wfx_get_gpio(struct device *dev, int override, - const char *label) +struct gpio_desc *wfx_get_gpio(struct device *dev, + int override, const char *label) { struct gpio_desc *ret; char label_buf[256]; @@ -187,18 +192,18 @@ struct gpio_desc *wfx_get_gpio(struct device *dev, int override, if (!ret || PTR_ERR(ret) == -ENOENT) dev_warn(dev, "gpio %s is not defined\n", label); else - dev_warn(dev, - "error while requesting gpio %s\n", label); + dev_warn(dev, "error while requesting gpio %s\n", + label); ret = NULL; } else { - dev_dbg(dev, - "using gpio %d for %s\n", desc_to_gpio(ret), label); + dev_dbg(dev, "using gpio %d for %s\n", + desc_to_gpio(ret), label); } return ret; } /* NOTE: wfx_send_pds() destroy buf */ -int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len) +int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len) { int ret; int start, brace_level, i; @@ -224,16 +229,19 @@ int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len) buf[i] = '}'; ret = hif_configuration(wdev, buf + start, i - start + 1); - if (ret == HIF_STATUS_FAILURE) { - dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", start, i); + if (ret > 0) { + dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", + start, i); return -EINVAL; } if (ret == -ETIMEDOUT) { - dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", start, i); + dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", + start, i); return ret; } if (ret) { - dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", start, i); + dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", + start, i); return -EIO; } buf[i] = ','; @@ -247,7 +255,7 @@ static int wfx_send_pdata_pds(struct wfx_dev *wdev) { int ret = 0; const struct firmware *pds; - unsigned char *tmp_buf; + u8 *tmp_buf; ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev); if (ret) { @@ -266,9 +274,9 @@ static void wfx_free_common(void *data) { struct wfx_dev *wdev = data; + mutex_destroy(&wdev->tx_power_loop_info_lock); mutex_destroy(&wdev->rx_stats_lock); mutex_destroy(&wdev->conf_mutex); - wfx_tx_queues_deinit(wdev); ieee80211_free_hw(wdev->hw); } @@ -286,7 +294,6 @@ struct wfx_dev *wfx_init_common(struct device *dev, SET_IEEE80211_DEV(hw, dev); - ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC); ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, CONNECTION_MONITOR); @@ -315,7 +322,7 @@ struct wfx_dev *wfx_init_common(struct device *dev, hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - hw->wiphy->max_ap_assoc_sta = WFX_MAX_STA_IN_AP_MODE; + hw->wiphy->max_ap_assoc_sta = HIF_LINK_ID_MAX; hw->wiphy->max_scan_ssids = 2; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations); @@ -338,7 +345,10 @@ struct wfx_dev *wfx_init_common(struct device *dev, mutex_init(&wdev->conf_mutex); mutex_init(&wdev->rx_stats_lock); + mutex_init(&wdev->tx_power_loop_info_lock); init_completion(&wdev->firmware_ready); + INIT_DELAYED_WORK(&wdev->cooling_timeout_work, + wfx_cooling_timeout_work); wfx_init_hif_cmd(&wdev->hif_cmd); wfx_tx_queues_init(wdev); @@ -359,23 +369,24 @@ int wfx_probe(struct wfx_dev *wdev) // prevent bh() to touch it. gpio_saved = wdev->pdata.gpio_wakeup; wdev->pdata.gpio_wakeup = NULL; + wdev->poll_irq = true; wfx_bh_register(wdev); err = wfx_init_device(wdev); if (err) - goto err1; + goto err0; - err = wait_for_completion_interruptible_timeout(&wdev->firmware_ready, - 10 * HZ); + wfx_bh_poll_irq(wdev); + err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ); if (err <= 0) { if (err == 0) { - dev_err(wdev->dev, "timeout while waiting for startup indication. IRQ configuration error?\n"); + dev_err(wdev->dev, "timeout while waiting for startup indication\n"); err = -ETIMEDOUT; } else if (err == -ERESTARTSYS) { dev_info(wdev->dev, "probe interrupted by user\n"); } - goto err1; + goto err0; } // FIXME: fill wiphy::hw_version @@ -384,7 +395,7 @@ int wfx_probe(struct wfx_dev *wdev) wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label, wdev->hw_caps.api_version_major, wdev->hw_caps.api_version_minor, - wdev->keyset, *((u32 *) &wdev->hw_caps.capabilities)); + wdev->keyset, *((u32 *)&wdev->hw_caps.capabilities)); snprintf(wdev->hw->wiphy->fw_version, sizeof(wdev->hw->wiphy->fw_version), "%d.%d.%d", @@ -397,14 +408,14 @@ int wfx_probe(struct wfx_dev *wdev) "unsupported firmware API version (expect 1 while firmware returns %d)\n", wdev->hw_caps.api_version_major); err = -ENOTSUPP; - goto err1; + goto err0; } err = wfx_sl_init(wdev); if (err && wdev->hw_caps.capabilities.link_mode == SEC_LINK_ENFORCED) { dev_err(wdev->dev, "chip require secure_link, but can't negociate it\n"); - goto err1; + goto err0; } if (wdev->hw_caps.regul_sel_mode_info.region_sel_mode) { @@ -417,7 +428,16 @@ int wfx_probe(struct wfx_dev *wdev) wdev->pdata.file_pds); err = wfx_send_pdata_pds(wdev); if (err < 0) - goto err1; + goto err0; + + wdev->poll_irq = false; + err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv); + if (err) + goto err0; + + err = hif_use_multi_tx_conf(wdev, true); + if (err) + dev_err(wdev->dev, "misconfigured IRQ?\n"); wdev->pdata.gpio_wakeup = gpio_saved; if (wdev->pdata.gpio_wakeup) { @@ -432,8 +452,6 @@ int wfx_probe(struct wfx_dev *wdev) hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE); } - hif_use_multi_tx_conf(wdev, true); - for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) { eth_zero_addr(wdev->addresses[i].addr); macaddr = of_get_mac_address(wdev->dev->of_node); @@ -466,8 +484,9 @@ int wfx_probe(struct wfx_dev *wdev) err2: ieee80211_unregister_hw(wdev->hw); - ieee80211_free_hw(wdev->hw); err1: + wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); +err0: wfx_bh_unregister(wdev); return err; } @@ -476,6 +495,7 @@ void wfx_release(struct wfx_dev *wdev) { ieee80211_unregister_hw(wdev->hw); hif_shutdown(wdev); + wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); wfx_bh_unregister(wdev); wfx_sl_deinit(wdev); } diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h index 9c9410072def..f832ce409fda 100644 --- a/drivers/staging/wfx/main.h +++ b/drivers/staging/wfx/main.h @@ -13,10 +13,10 @@ #include <linux/device.h> #include <linux/gpio/consumer.h> -#include "bus.h" #include "hif_api_general.h" struct wfx_dev; +struct hwbus_ops; struct wfx_platform_data { /* Keyset and ".sec" extention will appended to this string */ @@ -41,6 +41,6 @@ void wfx_release(struct wfx_dev *wdev); struct gpio_desc *wfx_get_gpio(struct device *dev, int override, const char *label); bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor); -int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len); +int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len); #endif diff --git a/drivers/staging/wfx/queue.c b/drivers/staging/wfx/queue.c index 39d9127ce4b9..3248ecefda56 100644 --- a/drivers/staging/wfx/queue.c +++ b/drivers/staging/wfx/queue.c @@ -35,6 +35,7 @@ void wfx_tx_flush(struct wfx_dev *wdev) if (wdev->chip_frozen) return; + wfx_tx_lock(wdev); mutex_lock(&wdev->hif_cmd.lock); ret = wait_event_timeout(wdev->hif.tx_buffers_empty, !wdev->hif.tx_buffers_used, @@ -44,9 +45,10 @@ void wfx_tx_flush(struct wfx_dev *wdev) wdev->hif.tx_buffers_used); wfx_pending_dump_old_frames(wdev, 3000); // FIXME: drop pending frames here - wdev->chip_frozen = 1; + wdev->chip_frozen = true; } mutex_unlock(&wdev->hif_cmd.lock); + wfx_tx_unlock(wdev); } void wfx_tx_lock_flush(struct wfx_dev *wdev) @@ -55,261 +57,142 @@ void wfx_tx_lock_flush(struct wfx_dev *wdev) wfx_tx_flush(wdev); } -void wfx_tx_queues_lock(struct wfx_dev *wdev) +void wfx_tx_queues_init(struct wfx_dev *wdev) { int i; - struct wfx_queue *queue; + skb_queue_head_init(&wdev->tx_pending); + init_waitqueue_head(&wdev->tx_dequeue); for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - queue = &wdev->tx_queue[i]; - spin_lock_bh(&queue->queue.lock); - if (queue->tx_locked_cnt++ == 0) - ieee80211_stop_queue(wdev->hw, queue->queue_id); - spin_unlock_bh(&queue->queue.lock); + skb_queue_head_init(&wdev->tx_queue[i].normal); + skb_queue_head_init(&wdev->tx_queue[i].cab); } } -void wfx_tx_queues_unlock(struct wfx_dev *wdev) +void wfx_tx_queues_check_empty(struct wfx_dev *wdev) { int i; - struct wfx_queue *queue; + WARN_ON(!skb_queue_empty_lockless(&wdev->tx_pending)); for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - queue = &wdev->tx_queue[i]; - spin_lock_bh(&queue->queue.lock); - WARN(!queue->tx_locked_cnt, "queue already unlocked"); - if (--queue->tx_locked_cnt == 0) - ieee80211_wake_queue(wdev->hw, queue->queue_id); - spin_unlock_bh(&queue->queue.lock); + WARN_ON(atomic_read(&wdev->tx_queue[i].pending_frames)); + WARN_ON(!skb_queue_empty_lockless(&wdev->tx_queue[i].normal)); + WARN_ON(!skb_queue_empty_lockless(&wdev->tx_queue[i].cab)); } } -/* If successful, LOCKS the TX queue! */ -void wfx_tx_queues_wait_empty_vif(struct wfx_vif *wvif) +static bool __wfx_tx_queue_empty(struct wfx_dev *wdev, + struct sk_buff_head *skb_queue, int vif_id) { - int i; - bool done; - struct wfx_queue *queue; - struct sk_buff *item; - struct wfx_dev *wdev = wvif->wdev; - struct hif_msg *hif; - - if (wvif->wdev->chip_frozen) { - wfx_tx_lock_flush(wdev); - wfx_tx_queues_clear(wdev); - return; - } + struct hif_msg *hif_msg; + struct sk_buff *skb; - do { - done = true; - wfx_tx_lock_flush(wdev); - for (i = 0; i < IEEE80211_NUM_ACS && done; ++i) { - queue = &wdev->tx_queue[i]; - spin_lock_bh(&queue->queue.lock); - skb_queue_walk(&queue->queue, item) { - hif = (struct hif_msg *) item->data; - if (hif->interface == wvif->id) - done = false; - } - spin_unlock_bh(&queue->queue.lock); - } - if (!done) { - wfx_tx_unlock(wdev); - msleep(20); + spin_lock_bh(&skb_queue->lock); + skb_queue_walk(skb_queue, skb) { + hif_msg = (struct hif_msg *)skb->data; + if (vif_id < 0 || hif_msg->interface == vif_id) { + spin_unlock_bh(&skb_queue->lock); + return false; } - } while (!done); -} - -static void wfx_tx_queue_clear(struct wfx_dev *wdev, struct wfx_queue *queue, - struct sk_buff_head *gc_list) -{ - int i; - struct sk_buff *item; - struct wfx_queue_stats *stats = &wdev->tx_queue_stats; - - spin_lock_bh(&queue->queue.lock); - while ((item = __skb_dequeue(&queue->queue)) != NULL) - skb_queue_head(gc_list, item); - spin_lock_nested(&stats->pending.lock, 1); - for (i = 0; i < ARRAY_SIZE(stats->link_map_cache); ++i) { - stats->link_map_cache[i] -= queue->link_map_cache[i]; - queue->link_map_cache[i] = 0; - } - spin_unlock(&stats->pending.lock); - spin_unlock_bh(&queue->queue.lock); -} - -void wfx_tx_queues_clear(struct wfx_dev *wdev) -{ - int i; - struct sk_buff *item; - struct sk_buff_head gc_list; - struct wfx_queue_stats *stats = &wdev->tx_queue_stats; - - skb_queue_head_init(&gc_list); - for (i = 0; i < IEEE80211_NUM_ACS; ++i) - wfx_tx_queue_clear(wdev, &wdev->tx_queue[i], &gc_list); - wake_up(&stats->wait_link_id_empty); - while ((item = skb_dequeue(&gc_list)) != NULL) - wfx_skb_dtor(wdev, item); -} - -void wfx_tx_queues_init(struct wfx_dev *wdev) -{ - int i; - - memset(&wdev->tx_queue_stats, 0, sizeof(wdev->tx_queue_stats)); - memset(wdev->tx_queue, 0, sizeof(wdev->tx_queue)); - skb_queue_head_init(&wdev->tx_queue_stats.pending); - init_waitqueue_head(&wdev->tx_queue_stats.wait_link_id_empty); - - for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - wdev->tx_queue[i].queue_id = i; - skb_queue_head_init(&wdev->tx_queue[i].queue); } + spin_unlock_bh(&skb_queue->lock); + return true; } -void wfx_tx_queues_deinit(struct wfx_dev *wdev) +bool wfx_tx_queue_empty(struct wfx_dev *wdev, + struct wfx_queue *queue, int vif_id) { - WARN_ON(!skb_queue_empty(&wdev->tx_queue_stats.pending)); - wfx_tx_queues_clear(wdev); + return __wfx_tx_queue_empty(wdev, &queue->normal, vif_id) && + __wfx_tx_queue_empty(wdev, &queue->cab, vif_id); } -int wfx_tx_queue_get_num_queued(struct wfx_queue *queue, u32 link_id_map) +static void __wfx_tx_queue_drop(struct wfx_dev *wdev, + struct sk_buff_head *skb_queue, int vif_id, + struct sk_buff_head *dropped) { - int ret, i; - - if (!link_id_map) - return 0; - - spin_lock_bh(&queue->queue.lock); - if (link_id_map == (u32)-1) { - ret = skb_queue_len(&queue->queue); - } else { - ret = 0; - for (i = 0; i < ARRAY_SIZE(queue->link_map_cache); i++) - if (link_id_map & BIT(i)) - ret += queue->link_map_cache[i]; + struct sk_buff *skb, *tmp; + struct hif_msg *hif_msg; + + spin_lock_bh(&skb_queue->lock); + skb_queue_walk_safe(skb_queue, skb, tmp) { + hif_msg = (struct hif_msg *)skb->data; + if (vif_id < 0 || hif_msg->interface == vif_id) { + __skb_unlink(skb, skb_queue); + skb_queue_head(dropped, skb); + } } - spin_unlock_bh(&queue->queue.lock); - return ret; + spin_unlock_bh(&skb_queue->lock); } -void wfx_tx_queue_put(struct wfx_dev *wdev, struct wfx_queue *queue, - struct sk_buff *skb) +void wfx_tx_queue_drop(struct wfx_dev *wdev, struct wfx_queue *queue, + int vif_id, struct sk_buff_head *dropped) { - struct wfx_queue_stats *stats = &wdev->tx_queue_stats; - struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); - - WARN(tx_priv->link_id >= ARRAY_SIZE(stats->link_map_cache), "invalid link-id value"); - spin_lock_bh(&queue->queue.lock); - __skb_queue_tail(&queue->queue, skb); - - ++queue->link_map_cache[tx_priv->link_id]; - - spin_lock_nested(&stats->pending.lock, 1); - ++stats->link_map_cache[tx_priv->link_id]; - spin_unlock(&stats->pending.lock); - spin_unlock_bh(&queue->queue.lock); -} - -static struct sk_buff *wfx_tx_queue_get(struct wfx_dev *wdev, - struct wfx_queue *queue, - u32 link_id_map) -{ - struct sk_buff *skb = NULL; - struct sk_buff *item; - struct wfx_queue_stats *stats = &wdev->tx_queue_stats; - struct wfx_tx_priv *tx_priv; - bool wakeup_stats = false; - - spin_lock_bh(&queue->queue.lock); - skb_queue_walk(&queue->queue, item) { - tx_priv = wfx_skb_tx_priv(item); - if (link_id_map & BIT(tx_priv->link_id)) { - skb = item; - break; - } - } - if (skb) { - tx_priv = wfx_skb_tx_priv(skb); - tx_priv->xmit_timestamp = ktime_get(); - __skb_unlink(skb, &queue->queue); - --queue->link_map_cache[tx_priv->link_id]; - - spin_lock_nested(&stats->pending.lock, 1); - __skb_queue_tail(&stats->pending, skb); - if (!--stats->link_map_cache[tx_priv->link_id]) - wakeup_stats = true; - spin_unlock(&stats->pending.lock); - } - spin_unlock_bh(&queue->queue.lock); - if (wakeup_stats) - wake_up(&stats->wait_link_id_empty); - return skb; + __wfx_tx_queue_drop(wdev, &queue->cab, vif_id, dropped); + __wfx_tx_queue_drop(wdev, &queue->normal, vif_id, dropped); + wake_up(&wdev->tx_dequeue); } -int wfx_pending_requeue(struct wfx_dev *wdev, struct sk_buff *skb) +void wfx_tx_queues_put(struct wfx_dev *wdev, struct sk_buff *skb) { - struct wfx_queue_stats *stats = &wdev->tx_queue_stats; - struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); struct wfx_queue *queue = &wdev->tx_queue[skb_get_queue_mapping(skb)]; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - WARN_ON(skb_get_queue_mapping(skb) > 3); - spin_lock_bh(&queue->queue.lock); - ++queue->link_map_cache[tx_priv->link_id]; - - spin_lock_nested(&stats->pending.lock, 1); - ++stats->link_map_cache[tx_priv->link_id]; - __skb_unlink(skb, &stats->pending); - spin_unlock(&stats->pending.lock); - __skb_queue_tail(&queue->queue, skb); - spin_unlock_bh(&queue->queue.lock); - return 0; + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + skb_queue_tail(&queue->cab, skb); + else + skb_queue_tail(&queue->normal, skb); } -int wfx_pending_remove(struct wfx_dev *wdev, struct sk_buff *skb) +void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped) { - struct wfx_queue_stats *stats = &wdev->tx_queue_stats; - - spin_lock_bh(&stats->pending.lock); - __skb_unlink(skb, &stats->pending); - spin_unlock_bh(&stats->pending.lock); - wfx_skb_dtor(wdev, skb); + struct wfx_queue *queue; + struct sk_buff *skb; - return 0; + WARN(!wdev->chip_frozen, "%s should only be used to recover a frozen device", + __func__); + while ((skb = skb_dequeue(&wdev->tx_pending)) != NULL) { + queue = &wdev->tx_queue[skb_get_queue_mapping(skb)]; + WARN_ON(skb_get_queue_mapping(skb) > 3); + WARN_ON(!atomic_read(&queue->pending_frames)); + atomic_dec(&queue->pending_frames); + skb_queue_head(dropped, skb); + } } struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id) { - struct sk_buff *skb; + struct wfx_queue *queue; struct hif_req_tx *req; - struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + struct sk_buff *skb; - spin_lock_bh(&stats->pending.lock); - skb_queue_walk(&stats->pending, skb) { + spin_lock_bh(&wdev->tx_pending.lock); + skb_queue_walk(&wdev->tx_pending, skb) { req = wfx_skb_txreq(skb); if (req->packet_id == packet_id) { - spin_unlock_bh(&stats->pending.lock); + spin_unlock_bh(&wdev->tx_pending.lock); + queue = &wdev->tx_queue[skb_get_queue_mapping(skb)]; + WARN_ON(skb_get_queue_mapping(skb) > 3); + WARN_ON(!atomic_read(&queue->pending_frames)); + atomic_dec(&queue->pending_frames); + skb_unlink(skb, &wdev->tx_pending); return skb; } } - spin_unlock_bh(&stats->pending.lock); + spin_unlock_bh(&wdev->tx_pending.lock); WARN(1, "cannot find packet in pending queue"); return NULL; } void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms) { - struct wfx_queue_stats *stats = &wdev->tx_queue_stats; ktime_t now = ktime_get(); struct wfx_tx_priv *tx_priv; struct hif_req_tx *req; struct sk_buff *skb; bool first = true; - spin_lock_bh(&stats->pending.lock); - skb_queue_walk(&stats->pending, skb) { + spin_lock_bh(&wdev->tx_pending.lock); + skb_queue_walk(&wdev->tx_pending, skb) { tx_priv = wfx_skb_tx_priv(skb); req = wfx_skb_txreq(skb); if (ktime_after(now, ktime_add_ms(tx_priv->xmit_timestamp, @@ -324,7 +207,7 @@ void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms) ktime_ms_delta(now, tx_priv->xmit_timestamp)); } } - spin_unlock_bh(&stats->pending.lock); + spin_unlock_bh(&wdev->tx_pending.lock); } unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, @@ -336,138 +219,66 @@ unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, return ktime_us_delta(now, tx_priv->xmit_timestamp); } -bool wfx_tx_queues_is_empty(struct wfx_dev *wdev) +bool wfx_tx_queues_has_cab(struct wfx_vif *wvif) { + struct wfx_dev *wdev = wvif->wdev; int i; - struct sk_buff_head *queue; - bool ret = true; - - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - queue = &wdev->tx_queue[i].queue; - spin_lock_bh(&queue->lock); - if (!skb_queue_empty(queue)) - ret = false; - spin_unlock_bh(&queue->lock); - } - return ret; -} - -static bool hif_handle_tx_data(struct wfx_vif *wvif, struct sk_buff *skb, - struct wfx_queue *queue) -{ - struct hif_req_tx *req = wfx_skb_txreq(skb); - struct ieee80211_key_conf *hw_key = wfx_skb_tx_priv(skb)->hw_key; - struct ieee80211_hdr *frame = - (struct ieee80211_hdr *)(req->frame + req->data_flags.fc_offset); - - // FIXME: mac80211 is smart enough to handle BSS loss. Driver should not - // try to do anything about that. - if (ieee80211_is_nullfunc(frame->frame_control)) { - mutex_lock(&wvif->bss_loss_lock); - if (wvif->bss_loss_state) { - wvif->bss_loss_confirm_id = req->packet_id; - req->queue_id.queue_id = HIF_QUEUE_ID_VOICE; - } - mutex_unlock(&wvif->bss_loss_lock); - } - // FIXME: identify the exact scenario matched by this condition. Does it - // happen yet? - if (ieee80211_has_protected(frame->frame_control) && - hw_key && hw_key->keyidx != wvif->wep_default_key_id && - (hw_key->cipher == WLAN_CIPHER_SUITE_WEP40 || - hw_key->cipher == WLAN_CIPHER_SUITE_WEP104)) { - wfx_tx_lock(wvif->wdev); - WARN_ON(wvif->wep_pending_skb); - wvif->wep_default_key_id = hw_key->keyidx; - wvif->wep_pending_skb = skb; - if (!schedule_work(&wvif->wep_key_work)) - wfx_tx_unlock(wvif->wdev); - return true; - } else { + if (wvif->vif->type != NL80211_IFTYPE_AP) return false; - } -} - -static int wfx_get_prio_queue(struct wfx_vif *wvif, - u32 tx_allowed_mask, int *total) -{ - static const int urgent = BIT(WFX_LINK_ID_AFTER_DTIM) | - BIT(WFX_LINK_ID_UAPSD); - const struct ieee80211_tx_queue_params *edca; - unsigned int score, best = -1; - int winner = -1; - int i; - - /* search for a winner using edca params */ - for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - int queued; - - edca = &wvif->edca_params[i]; - queued = wfx_tx_queue_get_num_queued(&wvif->wdev->tx_queue[i], - tx_allowed_mask); - if (!queued) - continue; - *total += queued; - score = ((edca->aifs + edca->cw_min) << 16) + - ((edca->cw_max - edca->cw_min) * - (get_random_int() & 0xFFFF)); - if (score < best && (winner < 0 || i != 3)) { - best = score; - winner = i; - } - } - - /* override winner if bursting */ - if (winner >= 0 && wvif->wdev->tx_burst_idx >= 0 && - winner != wvif->wdev->tx_burst_idx && - !wfx_tx_queue_get_num_queued(&wvif->wdev->tx_queue[winner], - tx_allowed_mask & urgent) && - wfx_tx_queue_get_num_queued(&wvif->wdev->tx_queue[wvif->wdev->tx_burst_idx], tx_allowed_mask)) - winner = wvif->wdev->tx_burst_idx; - - return winner; -} - -static int wfx_tx_queue_mask_get(struct wfx_vif *wvif, - struct wfx_queue **queue_p, - u32 *tx_allowed_mask_p) -{ - int idx; - u32 tx_allowed_mask; - int total = 0; - - /* Search for unicast traffic */ - tx_allowed_mask = ~wvif->sta_asleep_mask; - tx_allowed_mask |= BIT(WFX_LINK_ID_UAPSD); - if (wvif->sta_asleep_mask) - tx_allowed_mask &= ~BIT(WFX_LINK_ID_AFTER_DTIM); - else - tx_allowed_mask |= BIT(WFX_LINK_ID_AFTER_DTIM); - idx = wfx_get_prio_queue(wvif, tx_allowed_mask, &total); - if (idx < 0) - return -ENOENT; - - *queue_p = &wvif->wdev->tx_queue[idx]; - *tx_allowed_mask_p = tx_allowed_mask; - return 0; + for (i = 0; i < IEEE80211_NUM_ACS; ++i) + // Note: since only AP can have mcast frames in queue and only + // one vif can be AP, all queued frames has same interface id + if (!skb_queue_empty_lockless(&wdev->tx_queue[i].cab)) + return true; + return false; } -struct hif_msg *wfx_tx_queues_get_after_dtim(struct wfx_vif *wvif) +static struct sk_buff *wfx_tx_queues_get_skb(struct wfx_dev *wdev) { - struct wfx_dev *wdev = wvif->wdev; - struct ieee80211_tx_info *tx_info; + struct wfx_queue *sorted_queues[IEEE80211_NUM_ACS]; + struct wfx_vif *wvif; struct hif_msg *hif; struct sk_buff *skb; - int i; + int i, j; - for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - skb_queue_walk(&wdev->tx_queue[i].queue, skb) { - tx_info = IEEE80211_SKB_CB(skb); + // bubble sort + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + sorted_queues[i] = &wdev->tx_queue[i]; + for (j = i; j > 0; j--) + if (atomic_read(&sorted_queues[j]->pending_frames) > + atomic_read(&sorted_queues[j - 1]->pending_frames)) + swap(sorted_queues[j - 1], sorted_queues[j]); + } + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + if (!wvif->after_dtim_tx_allowed) + continue; + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + skb = skb_dequeue(&sorted_queues[i]->cab); + if (!skb) + continue; + // Note: since only AP can have mcast frames in queue + // and only one vif can be AP, all queued frames has + // same interface id hif = (struct hif_msg *)skb->data; - if ((tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) && - (hif->interface == wvif->id)) - return (struct hif_msg *)skb->data; + WARN_ON(hif->interface != wvif->id); + WARN_ON(sorted_queues[i] != + &wdev->tx_queue[skb_get_queue_mapping(skb)]); + atomic_inc(&sorted_queues[i]->pending_frames); + return skb; + } + // No more multicast to sent + wvif->after_dtim_tx_allowed = false; + schedule_work(&wvif->update_tim_work); + } + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + skb = skb_dequeue(&sorted_queues[i]->normal); + if (skb) { + WARN_ON(sorted_queues[i] != + &wdev->tx_queue[skb_get_queue_mapping(skb)]); + atomic_inc(&sorted_queues[i]->pending_frames); + return skb; } } return NULL; @@ -475,90 +286,20 @@ struct hif_msg *wfx_tx_queues_get_after_dtim(struct wfx_vif *wvif) struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev) { + struct wfx_tx_priv *tx_priv; struct sk_buff *skb; - struct hif_msg *hif = NULL; - struct wfx_queue *queue = NULL; - struct wfx_queue *vif_queue = NULL; - u32 tx_allowed_mask = 0; - u32 vif_tx_allowed_mask = 0; - struct wfx_vif *wvif; - int not_found; - int burst; - int i; if (atomic_read(&wdev->tx_lock)) return NULL; - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - if (wvif->after_dtim_tx_allowed) { - for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - skb = wfx_tx_queue_get(wvif->wdev, - &wdev->tx_queue[i], - BIT(WFX_LINK_ID_AFTER_DTIM)); - if (skb) { - hif = (struct hif_msg *)skb->data; - // Cannot happen since only one vif can - // be AP at time - WARN_ON(wvif->id != hif->interface); - return hif; - } - } - // No more multicast to sent - wvif->after_dtim_tx_allowed = false; - schedule_work(&wvif->update_tim_work); - } - } - for (;;) { - int ret = -ENOENT; - int queue_num; - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - spin_lock_bh(&wvif->ps_state_lock); - - not_found = wfx_tx_queue_mask_get(wvif, &vif_queue, - &vif_tx_allowed_mask); - - spin_unlock_bh(&wvif->ps_state_lock); - - if (!not_found) { - if (queue && queue != vif_queue) - dev_info(wdev->dev, "vifs disagree about queue priority\n"); - tx_allowed_mask |= vif_tx_allowed_mask; - queue = vif_queue; - ret = 0; - } - } - - if (ret) - return NULL; - - queue_num = queue - wdev->tx_queue; - - skb = wfx_tx_queue_get(wdev, queue, tx_allowed_mask); + skb = wfx_tx_queues_get_skb(wdev); if (!skb) - continue; - hif = (struct hif_msg *)skb->data; - wvif = wdev_to_wvif(wdev, hif->interface); - WARN_ON(!wvif); - - if (hif_handle_tx_data(wvif, skb, queue)) - continue; /* Handled by WSM */ - - /* allow bursting if txop is set */ - if (wvif->edca_params[queue_num].txop) - burst = wfx_tx_queue_get_num_queued(queue, tx_allowed_mask) + 1; - else - burst = 1; - - /* store index of bursting queue */ - if (burst > 1) - wdev->tx_burst_idx = queue_num; - else - wdev->tx_burst_idx = -1; - - return hif; + return NULL; + skb_queue_tail(&wdev->tx_pending, skb); + wake_up(&wdev->tx_dequeue); + tx_priv = wfx_skb_tx_priv(skb); + tx_priv->xmit_timestamp = ktime_get(); + return (struct hif_msg *)skb->data; } } diff --git a/drivers/staging/wfx/queue.h b/drivers/staging/wfx/queue.h index 90bb060d1204..0c3b7244498e 100644 --- a/drivers/staging/wfx/queue.h +++ b/drivers/staging/wfx/queue.h @@ -9,29 +9,15 @@ #define WFX_QUEUE_H #include <linux/skbuff.h> - -#include "hif_api_cmd.h" - -#define WFX_MAX_STA_IN_AP_MODE 14 -#define WFX_LINK_ID_NO_ASSOC 15 -#define WFX_LINK_ID_AFTER_DTIM (WFX_LINK_ID_NO_ASSOC + 1) -#define WFX_LINK_ID_UAPSD (WFX_LINK_ID_NO_ASSOC + 2) -#define WFX_LINK_ID_MAX (WFX_LINK_ID_NO_ASSOC + 3) +#include <linux/atomic.h> struct wfx_dev; struct wfx_vif; struct wfx_queue { - struct sk_buff_head queue; - int tx_locked_cnt; - int link_map_cache[WFX_LINK_ID_MAX]; - u8 queue_id; -}; - -struct wfx_queue_stats { - int link_map_cache[WFX_LINK_ID_MAX]; - struct sk_buff_head pending; - wait_queue_head_t wait_link_id_empty; + struct sk_buff_head normal; + struct sk_buff_head cab; // Content After (DTIM) Beacon + atomic_t pending_frames; }; void wfx_tx_lock(struct wfx_dev *wdev); @@ -40,22 +26,18 @@ void wfx_tx_flush(struct wfx_dev *wdev); void wfx_tx_lock_flush(struct wfx_dev *wdev); void wfx_tx_queues_init(struct wfx_dev *wdev); -void wfx_tx_queues_deinit(struct wfx_dev *wdev); -void wfx_tx_queues_lock(struct wfx_dev *wdev); -void wfx_tx_queues_unlock(struct wfx_dev *wdev); -void wfx_tx_queues_clear(struct wfx_dev *wdev); -bool wfx_tx_queues_is_empty(struct wfx_dev *wdev); -void wfx_tx_queues_wait_empty_vif(struct wfx_vif *wvif); +void wfx_tx_queues_check_empty(struct wfx_dev *wdev); +bool wfx_tx_queues_has_cab(struct wfx_vif *wvif); +void wfx_tx_queues_put(struct wfx_dev *wdev, struct sk_buff *skb); struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev); -struct hif_msg *wfx_tx_queues_get_after_dtim(struct wfx_vif *wvif); -void wfx_tx_queue_put(struct wfx_dev *wdev, struct wfx_queue *queue, - struct sk_buff *skb); -int wfx_tx_queue_get_num_queued(struct wfx_queue *queue, u32 link_id_map); +bool wfx_tx_queue_empty(struct wfx_dev *wdev, struct wfx_queue *queue, + int vif_id); +void wfx_tx_queue_drop(struct wfx_dev *wdev, struct wfx_queue *queue, + int vif_id, struct sk_buff_head *dropped); struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id); -int wfx_pending_remove(struct wfx_dev *wdev, struct sk_buff *skb); -int wfx_pending_requeue(struct wfx_dev *wdev, struct sk_buff *skb); +void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped); unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, struct sk_buff *skb); void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms); diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c index 9aa14331affd..57ea9997800b 100644 --- a/drivers/staging/wfx/scan.c +++ b/drivers/staging/wfx/scan.c @@ -88,18 +88,22 @@ void wfx_hw_scan_work(struct work_struct *work) struct ieee80211_scan_request *hw_req = wvif->scan_req; int chan_cur, ret; - mutex_lock(&wvif->scan_lock); mutex_lock(&wvif->wdev->conf_mutex); + mutex_lock(&wvif->scan_lock); + if (wvif->join_in_progress) { + dev_info(wvif->wdev->dev, "%s: abort in-progress REQ_JOIN", + __func__); + wfx_reset(wvif); + } update_probe_tmpl(wvif, &hw_req->req); - wfx_fwd_probe_req(wvif, true); chan_cur = 0; do { ret = send_scan_req(wvif, &hw_req->req, chan_cur); if (ret > 0) chan_cur += ret; } while (ret > 0 && chan_cur < hw_req->req.n_channels); - mutex_unlock(&wvif->wdev->conf_mutex); mutex_unlock(&wvif->scan_lock); + mutex_unlock(&wvif->wdev->conf_mutex); __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0); } @@ -113,9 +117,6 @@ int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_AP) return -EOPNOTSUPP; - if (wvif->state == WFX_STATE_PRE_STA) - return -EBUSY; - wvif->scan_req = hw_req; schedule_work(&wvif->scan_work); return 0; diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c index 9d430346a58b..12e8a5b638f1 100644 --- a/drivers/staging/wfx/sta.c +++ b/drivers/staging/wfx/sta.c @@ -5,6 +5,7 @@ * Copyright (c) 2017-2019, Silicon Laboratories, Inc. * Copyright (c) 2010, ST-Ericsson */ +#include <linux/etherdevice.h> #include <net/mac80211.h> #include "sta.h" @@ -37,117 +38,32 @@ u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates) return ret; } -static void __wfx_free_event_queue(struct list_head *list) +void wfx_cooling_timeout_work(struct work_struct *work) { - struct wfx_hif_event *event, *tmp; + struct wfx_dev *wdev = container_of(to_delayed_work(work), + struct wfx_dev, + cooling_timeout_work); - list_for_each_entry_safe(event, tmp, list, link) { - list_del(&event->link); - kfree(event); - } -} - -static void wfx_free_event_queue(struct wfx_vif *wvif) -{ - LIST_HEAD(list); - - spin_lock(&wvif->event_queue_lock); - list_splice_init(&wvif->event_queue, &list); - spin_unlock(&wvif->event_queue_lock); - - __wfx_free_event_queue(&list); + wdev->chip_frozen = true; + wfx_tx_unlock(wdev); } -void wfx_cqm_bssloss_sm(struct wfx_vif *wvif, int init, int good, int bad) +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd) { - int tx = 0; - - mutex_lock(&wvif->bss_loss_lock); - cancel_work_sync(&wvif->bss_params_work); - - if (init) { - schedule_delayed_work(&wvif->bss_loss_work, HZ); - wvif->bss_loss_state = 0; - - if (!atomic_read(&wvif->wdev->tx_lock)) - tx = 1; - } else if (good) { - cancel_delayed_work_sync(&wvif->bss_loss_work); - wvif->bss_loss_state = 0; - schedule_work(&wvif->bss_params_work); - } else if (bad) { - /* FIXME Should we just keep going until we time out? */ - if (wvif->bss_loss_state < 3) - tx = 1; + if (cmd == STA_NOTIFY_AWAKE) { + // Device recover normal temperature + if (cancel_delayed_work(&wdev->cooling_timeout_work)) + wfx_tx_unlock(wdev); } else { - cancel_delayed_work_sync(&wvif->bss_loss_work); - wvif->bss_loss_state = 0; - } - - /* Spit out a NULL packet to our AP if necessary */ - // FIXME: call ieee80211_beacon_loss/ieee80211_connection_loss instead - if (tx) { - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - struct ieee80211_tx_control control = { }; - - wvif->bss_loss_state++; - - skb = ieee80211_nullfunc_get(wvif->wdev->hw, wvif->vif, false); - if (!skb) - goto end; - hdr = (struct ieee80211_hdr *)skb->data; - memset(IEEE80211_SKB_CB(skb), 0, - sizeof(*IEEE80211_SKB_CB(skb))); - IEEE80211_SKB_CB(skb)->control.vif = wvif->vif; - IEEE80211_SKB_CB(skb)->driver_rates[0].idx = 0; - IEEE80211_SKB_CB(skb)->driver_rates[0].count = 1; - IEEE80211_SKB_CB(skb)->driver_rates[1].idx = -1; - rcu_read_lock(); // protect control.sta - control.sta = ieee80211_find_sta(wvif->vif, hdr->addr1); - wfx_tx(wvif->wdev->hw, &control, skb); - rcu_read_unlock(); + // Device is too hot + schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ); + wfx_tx_lock(wdev); } -end: - mutex_unlock(&wvif->bss_loss_lock); -} - -int wfx_fwd_probe_req(struct wfx_vif *wvif, bool enable) -{ - wvif->fwd_probe_req = enable; - return hif_set_rx_filter(wvif, wvif->filter_bssid, - wvif->fwd_probe_req); -} - -static int wfx_set_mcast_filter(struct wfx_vif *wvif, - struct wfx_grp_addr_table *fp) -{ - int i; - - // Temporary workaround for filters - return hif_set_data_filtering(wvif, false, true); - - if (!fp->enable) - return hif_set_data_filtering(wvif, false, true); - - for (i = 0; i < fp->num_addresses; i++) - hif_set_mac_addr_condition(wvif, i, fp->address_list[i]); - hif_set_uc_mc_bc_condition(wvif, 0, - HIF_FILTER_UNICAST | HIF_FILTER_BROADCAST); - hif_set_config_data_filter(wvif, true, 0, BIT(1), - BIT(fp->num_addresses) - 1); - hif_set_data_filtering(wvif, true, true); - - return 0; } -void wfx_update_filtering(struct wfx_vif *wvif) +static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon) { - int ret; - int bf_enable; - int bf_count; - int n_filter_ies; - struct hif_ie_table_entry filter_ies[] = { + const struct hif_ie_table_entry filter_ies[] = { { .ie_id = WLAN_EID_VENDOR_SPECIFIC, .has_changed = 1, @@ -167,40 +83,33 @@ void wfx_update_filtering(struct wfx_vif *wvif) } }; - if (wvif->state == WFX_STATE_PASSIVE) - return; - - if (wvif->disable_beacon_filter) { - bf_enable = 0; - bf_count = 1; - n_filter_ies = 0; - } else if (wvif->vif->type != NL80211_IFTYPE_STATION) { - bf_enable = HIF_BEACON_FILTER_ENABLE | HIF_BEACON_FILTER_AUTO_ERP; - bf_count = 0; - n_filter_ies = 2; + if (!filter_beacon) { + hif_beacon_filter_control(wvif, 0, 1); } else { - bf_enable = HIF_BEACON_FILTER_ENABLE; - bf_count = 0; - n_filter_ies = 3; + hif_set_beacon_filter_table(wvif, 3, filter_ies); + hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE, 0); } - - ret = hif_set_rx_filter(wvif, wvif->filter_bssid, wvif->fwd_probe_req); - if (!ret) - ret = hif_set_beacon_filter_table(wvif, n_filter_ies, filter_ies); - if (!ret) - ret = hif_beacon_filter_control(wvif, bf_enable, bf_count); - if (!ret) - ret = wfx_set_mcast_filter(wvif, &wvif->mcast_filter); - if (ret) - dev_err(wvif->wdev->dev, "update filtering failed: %d\n", ret); } -static void wfx_update_filtering_work(struct work_struct *work) +static void wfx_filter_mcast(struct wfx_vif *wvif, bool filter_mcast) { - struct wfx_vif *wvif = container_of(work, struct wfx_vif, - update_filtering_work); + int i; - wfx_update_filtering(wvif); + // Temporary workaround for filters + hif_set_data_filtering(wvif, false, true); + return; + + if (!filter_mcast) { + hif_set_data_filtering(wvif, false, true); + return; + } + for (i = 0; i < wvif->filter_mcast_count; i++) + hif_set_mac_addr_condition(wvif, i, wvif->filter_mcast_addr[i]); + hif_set_uc_mc_bc_condition(wvif, 0, + HIF_FILTER_UNICAST | HIF_FILTER_BROADCAST); + hif_set_config_data_filter(wvif, true, 0, BIT(1), + BIT(wvif->filter_mcast_count) - 1); + hif_set_data_filtering(wvif, true, true); } u64 wfx_prepare_multicast(struct ieee80211_hw *hw, @@ -213,72 +122,127 @@ u64 wfx_prepare_multicast(struct ieee80211_hw *hw, int count = netdev_hw_addr_list_count(mc_list); while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - memset(&wvif->mcast_filter, 0x00, sizeof(wvif->mcast_filter)); - if (!count || - count > ARRAY_SIZE(wvif->mcast_filter.address_list)) + if (count > ARRAY_SIZE(wvif->filter_mcast_addr)) { + wvif->filter_mcast_count = 0; continue; + } + wvif->filter_mcast_count = count; i = 0; netdev_hw_addr_list_for_each(ha, mc_list) { - ether_addr_copy(wvif->mcast_filter.address_list[i], - ha->addr); + ether_addr_copy(wvif->filter_mcast_addr[i], ha->addr); i++; } - wvif->mcast_filter.enable = true; - wvif->mcast_filter.num_addresses = count; } return 0; } -void wfx_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 unused) +void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 unused) { struct wfx_vif *wvif = NULL; struct wfx_dev *wdev = hw->priv; + bool filter_bssid, filter_prbreq, filter_beacon, filter_mcast; + + // Notes: + // - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered + // - PS-Poll (FIF_PSPOLL) are never filtered + // - RTS, CTS and Ack (FIF_CONTROL) are always filtered + // - Broken frames (FIF_FCSFAIL and FIF_PLCPFAIL) are always filtered + // - Firmware does (yet) allow to forward unicast traffic sent to + // other stations (aka. promiscuous mode) + *total_flags &= FIF_BCN_PRBRESP_PROMISC | FIF_ALLMULTI | FIF_OTHER_BSS | + FIF_PROBE_REQ | FIF_PSPOLL; - *total_flags &= FIF_OTHER_BSS | FIF_FCSFAIL | FIF_PROBE_REQ; - + mutex_lock(&wdev->conf_mutex); while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { mutex_lock(&wvif->scan_lock); - wvif->filter_bssid = (*total_flags & - (FIF_OTHER_BSS | FIF_PROBE_REQ)) ? 0 : 1; - wvif->disable_beacon_filter = !(*total_flags & FIF_PROBE_REQ); - wfx_fwd_probe_req(wvif, true); - wfx_update_filtering(wvif); + + // Note: FIF_BCN_PRBRESP_PROMISC covers probe response and + // beacons from other BSS + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + filter_beacon = false; + else + filter_beacon = true; + wfx_filter_beacon(wvif, filter_beacon); + + if (*total_flags & FIF_ALLMULTI) { + filter_mcast = false; + } else if (!wvif->filter_mcast_count) { + dev_dbg(wdev->dev, "disabling unconfigured multicast filter"); + filter_mcast = false; + } else { + filter_mcast = true; + } + wfx_filter_mcast(wvif, filter_mcast); + + if (*total_flags & FIF_OTHER_BSS) + filter_bssid = false; + else + filter_bssid = true; + + // In AP mode, chip can reply to probe request itself + if (*total_flags & FIF_PROBE_REQ && + wvif->vif->type == NL80211_IFTYPE_AP) { + dev_dbg(wdev->dev, "do not forward probe request in AP mode\n"); + *total_flags &= ~FIF_PROBE_REQ; + } + + if (*total_flags & FIF_PROBE_REQ) + filter_prbreq = false; + else + filter_prbreq = true; + hif_set_rx_filter(wvif, filter_bssid, filter_prbreq); + mutex_unlock(&wvif->scan_lock); } + mutex_unlock(&wdev->conf_mutex); } -static int wfx_update_pm(struct wfx_vif *wvif) +int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) { - struct ieee80211_conf *conf = &wvif->wdev->hw->conf; - bool ps = conf->flags & IEEE80211_CONF_PS; - int ps_timeout = conf->dynamic_ps_timeout; struct ieee80211_channel *chan0 = NULL, *chan1 = NULL; + struct ieee80211_conf *conf = &wvif->wdev->hw->conf; - WARN_ON(conf->dynamic_ps_timeout < 0); - if (wvif->state != WFX_STATE_STA || !wvif->bss_params.aid) - return 0; - if (!ps) - ps_timeout = 0; - if (wvif->uapsd_mask) - ps_timeout = 0; - - // Kernel disable powersave when an AP is in use. In contrary, it is - // absolutely necessary to enable legacy powersave for WF200 if channels - // are differents. + WARN(!wvif->vif->bss_conf.assoc && enable_ps, + "enable_ps is reliable only if associated"); if (wdev_to_wvif(wvif->wdev, 0)) chan0 = wdev_to_wvif(wvif->wdev, 0)->vif->bss_conf.chandef.chan; if (wdev_to_wvif(wvif->wdev, 1)) chan1 = wdev_to_wvif(wvif->wdev, 1)->vif->bss_conf.chandef.chan; if (chan0 && chan1 && chan0->hw_value != chan1->hw_value && wvif->vif->type != NL80211_IFTYPE_AP) { - ps = true; - ps_timeout = 0; + // It is necessary to enable powersave if channels + // are differents. + if (enable_ps) + *enable_ps = true; + if (wvif->bss_not_support_ps_poll) + return 30; + else + return 0; } + if (enable_ps) + *enable_ps = wvif->vif->bss_conf.ps; + if (wvif->vif->bss_conf.assoc && wvif->vif->bss_conf.ps) + return conf->dynamic_ps_timeout; + else + return -1; +} + +int wfx_update_pm(struct wfx_vif *wvif) +{ + int ps_timeout; + bool ps; + + if (!wvif->vif->bss_conf.assoc) + return 0; + ps_timeout = wfx_get_ps_timeout(wvif, &ps); + if (!ps) + ps_timeout = 0; + WARN_ON(ps_timeout < 0); + if (wvif->uapsd_mask) + ps_timeout = 0; if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete, TU_TO_JIFFIES(512))) @@ -287,18 +251,25 @@ static int wfx_update_pm(struct wfx_vif *wvif) return hif_set_pm(wvif, ps, ps_timeout); } +static void wfx_update_pm_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, + update_pm_work); + + wfx_update_pm(wvif); +} + int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; int old_uapsd = wvif->uapsd_mask; WARN_ON(queue >= hw->queues); mutex_lock(&wdev->conf_mutex); assign_bit(queue, &wvif->uapsd_mask, params->uapsd); - memcpy(&wvif->edca_params[queue], params, sizeof(*params)); hif_set_edca_queue_params(wvif, queue, params); if (wvif->vif->type == NL80211_IFTYPE_STATION && old_uapsd != wvif->uapsd_mask) { @@ -319,32 +290,9 @@ int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return 0; } -static int __wfx_flush(struct wfx_dev *wdev, bool drop) -{ - for (;;) { - if (drop) - wfx_tx_queues_clear(wdev); - if (wait_event_timeout(wdev->tx_queue_stats.wait_link_id_empty, - wfx_tx_queues_is_empty(wdev), - 2 * HZ) <= 0) - return -ETIMEDOUT; - wfx_tx_flush(wdev); - if (wfx_tx_queues_is_empty(wdev)) - return 0; - dev_warn(wdev->dev, "frames queued while flushing tx queues"); - } -} - -void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) -{ - // FIXME: only flush requested vif and queues - __wfx_flush(hw->priv, drop); -} - /* WSM callbacks */ -static void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) +void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) { /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 * RSSI = RCPI / 2 - 110 @@ -360,100 +308,23 @@ static void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL); } -static void wfx_event_handler_work(struct work_struct *work) +static void wfx_beacon_loss_work(struct work_struct *work) { - struct wfx_vif *wvif = - container_of(work, struct wfx_vif, event_handler_work); - struct wfx_hif_event *event; - - LIST_HEAD(list); - - spin_lock(&wvif->event_queue_lock); - list_splice_init(&wvif->event_queue, &list); - spin_unlock(&wvif->event_queue_lock); - - list_for_each_entry(event, &list, link) { - switch (event->evt.event_id) { - case HIF_EVENT_IND_BSSLOST: - cancel_work_sync(&wvif->unjoin_work); - mutex_lock(&wvif->scan_lock); - wfx_cqm_bssloss_sm(wvif, 1, 0, 0); - mutex_unlock(&wvif->scan_lock); - break; - case HIF_EVENT_IND_BSSREGAINED: - wfx_cqm_bssloss_sm(wvif, 0, 0, 0); - cancel_work_sync(&wvif->unjoin_work); - break; - case HIF_EVENT_IND_RCPI_RSSI: - wfx_event_report_rssi(wvif, - event->evt.event_data.rcpi_rssi); - break; - case HIF_EVENT_IND_PS_MODE_ERROR: - dev_warn(wvif->wdev->dev, - "error while processing power save request\n"); - break; - default: - dev_warn(wvif->wdev->dev, - "unhandled event indication: %.2x\n", - event->evt.event_id); - break; - } - } - __wfx_free_event_queue(&list); -} - -static void wfx_bss_loss_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(work, struct wfx_vif, - bss_loss_work.work); - - ieee80211_connection_loss(wvif->vif); -} - -static void wfx_bss_params_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(work, struct wfx_vif, - bss_params_work); + struct wfx_vif *wvif = container_of(to_delayed_work(work), + struct wfx_vif, beacon_loss_work); + struct ieee80211_bss_conf *bss_conf = &wvif->vif->bss_conf; - mutex_lock(&wvif->wdev->conf_mutex); - wvif->bss_params.bss_flags.lost_count_only = 1; - hif_set_bss_params(wvif, &wvif->bss_params); - wvif->bss_params.bss_flags.lost_count_only = 0; - mutex_unlock(&wvif->wdev->conf_mutex); + ieee80211_beacon_loss(wvif->vif); + schedule_delayed_work(to_delayed_work(work), + msecs_to_jiffies(bss_conf->beacon_int)); } -static void wfx_do_unjoin(struct wfx_vif *wvif) +void wfx_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int idx) { - mutex_lock(&wvif->wdev->conf_mutex); - - if (!wvif->state) - goto done; - - if (wvif->state == WFX_STATE_AP) - goto done; - - cancel_work_sync(&wvif->update_filtering_work); - wvif->state = WFX_STATE_PASSIVE; - - /* Unjoin is a reset. */ - wfx_tx_flush(wvif->wdev); - hif_keep_alive_period(wvif, 0); - hif_reset(wvif, false); - wfx_tx_policy_init(wvif); - hif_set_macaddr(wvif, wvif->vif->addr); - wfx_free_event_queue(wvif); - cancel_work_sync(&wvif->event_handler_work); - wfx_cqm_bssloss_sm(wvif, 0, 0, 0); + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - /* Disable Block ACKs */ - hif_set_block_ack_policy(wvif, 0, 0); - - wvif->disable_beacon_filter = false; - wfx_update_filtering(wvif); - memset(&wvif->bss_params, 0, sizeof(wvif->bss_params)); - -done: - mutex_unlock(&wvif->wdev->conf_mutex); + hif_wep_default_key_id(wvif, idx); } static void wfx_set_mfp(struct wfx_vif *wvif, @@ -472,8 +343,7 @@ static void wfx_set_mfp(struct wfx_vif *wvif, rcu_read_lock(); if (bss) - ptr = (const u16 *) ieee80211_bss_get_ie(bss, - WLAN_EID_RSN); + ptr = (const u16 *)ieee80211_bss_get_ie(bss, WLAN_EID_RSN); if (ptr) { ptr += pairwise_cipher_suite_count_offset; @@ -487,6 +357,24 @@ static void wfx_set_mfp(struct wfx_vif *wvif, hif_set_mfp(wvif, mfpc, mfpr); } +void wfx_reset(struct wfx_vif *wvif) +{ + struct wfx_dev *wdev = wvif->wdev; + + wfx_tx_lock_flush(wdev); + hif_reset(wvif, false); + wfx_tx_policy_init(wvif); + if (wvif_count(wdev) <= 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + wfx_tx_unlock(wdev); + wvif->join_in_progress = false; + wvif->bss_not_support_ps_poll = false; + cancel_delayed_work_sync(&wvif->beacon_loss_work); + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_update_pm(wvif); +} + static void wfx_do_join(struct wfx_vif *wvif) { int ret; @@ -498,9 +386,6 @@ static void wfx_do_join(struct wfx_vif *wvif) wfx_tx_lock_flush(wvif->wdev); - if (wvif->state) - wfx_do_unjoin(wvif); - bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, conf->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); @@ -509,109 +394,72 @@ static void wfx_do_join(struct wfx_vif *wvif) return; } - mutex_lock(&wvif->wdev->conf_mutex); - - /* Sanity check beacon interval */ - if (!wvif->beacon_int) - wvif->beacon_int = 1; - rcu_read_lock(); // protect ssidie - if (!conf->ibss_joined) + if (bss) ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); if (ssidie) { ssidlen = ssidie[1]; - memcpy(ssid, &ssidie[2], ssidie[1]); + if (ssidlen > IEEE80211_MAX_SSID_LEN) + ssidlen = IEEE80211_MAX_SSID_LEN; + memcpy(ssid, &ssidie[2], ssidlen); } rcu_read_unlock(); - wfx_tx_flush(wvif->wdev); - - if (wvif_count(wvif->wdev) <= 1) - hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - wfx_set_mfp(wvif, bss); + cfg80211_put_bss(wvif->wdev->hw->wiphy, bss); - wvif->wdev->tx_burst_idx = -1; + wvif->join_in_progress = true; ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen); if (ret) { ieee80211_connection_loss(wvif->vif); - wvif->join_complete_status = -1; - /* Tx lock still held, unjoin will clear it. */ - if (!schedule_work(&wvif->unjoin_work)) - wfx_tx_unlock(wvif->wdev); + wfx_reset(wvif); } else { - wvif->join_complete_status = 0; - if (wvif->vif->type == NL80211_IFTYPE_ADHOC) - wvif->state = WFX_STATE_IBSS; - else - wvif->state = WFX_STATE_PRE_STA; - wfx_tx_unlock(wvif->wdev); - - /* Upload keys */ - wfx_upload_keys(wvif); - /* Due to beacon filtering it is possible that the * AP's beacon is not known for the mac80211 stack. * Disable filtering temporary to make sure the stack * receives at least one */ - wvif->disable_beacon_filter = true; + wfx_filter_beacon(wvif, false); } - wfx_update_filtering(wvif); - - mutex_unlock(&wvif->wdev->conf_mutex); - if (bss) - cfg80211_put_bss(wvif->wdev->hw->wiphy, bss); -} - -static void wfx_unjoin_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(work, struct wfx_vif, unjoin_work); - - wfx_do_unjoin(wvif); wfx_tx_unlock(wvif->wdev); } int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; - struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *) &sta->drv_priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; spin_lock_init(&sta_priv->lock); sta_priv->vif_id = wvif->id; - // FIXME: in station mode, the current API interprets new link-id as a - // tdls peer. - if (vif->type == NL80211_IFTYPE_STATION) + // In station mode, the firmware interprets new link-id as a TDLS peer. + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) return 0; sta_priv->link_id = ffz(wvif->link_id_map); wvif->link_id_map |= BIT(sta_priv->link_id); WARN_ON(!sta_priv->link_id); - WARN_ON(sta_priv->link_id >= WFX_MAX_STA_IN_AP_MODE); + WARN_ON(sta_priv->link_id >= HIF_LINK_ID_MAX); hif_map_link(wvif, sta->addr, 0, sta_priv->link_id); - spin_lock_bh(&wvif->ps_state_lock); - if ((sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) == - IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) - wvif->sta_asleep_mask |= BIT(sta_priv->link_id); - spin_unlock_bh(&wvif->ps_state_lock); return 0; } int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; - struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *) &sta->drv_priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; int i; for (i = 0; i < ARRAY_SIZE(sta_priv->buffered); i++) if (sta_priv->buffered[i]) - dev_warn(wvif->wdev->dev, "release station while %d pending frame on queue %d", - sta_priv->buffered[i], i); - // FIXME: see note in wfx_sta_add() - if (vif->type == NL80211_IFTYPE_STATION) + // Not an error if paired with trace in + // wfx_tx_update_sta() + dev_dbg(wvif->wdev->dev, "release station while %d pending frame on queue %d", + sta_priv->buffered[i], i); + // See note in wfx_sta_add() + if (!sta_priv->link_id) return 0; // FIXME add a mutex? hif_map_link(wvif, sta->addr, 1, sta_priv->link_id); @@ -619,50 +467,10 @@ int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } -static int wfx_start_ap(struct wfx_vif *wvif) -{ - int ret; - - wvif->beacon_int = wvif->vif->bss_conf.beacon_int; - wvif->wdev->tx_burst_idx = -1; - ret = hif_start(wvif, &wvif->vif->bss_conf, wvif->channel); - if (ret) - return ret; - ret = wfx_upload_keys(wvif); - if (ret) - return ret; - if (wvif_count(wvif->wdev) <= 1) - hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - wvif->state = WFX_STATE_AP; - wfx_update_filtering(wvif); - return 0; -} - -static int wfx_update_beaconing(struct wfx_vif *wvif) -{ - if (wvif->vif->type != NL80211_IFTYPE_AP) - return 0; - if (wvif->state == WFX_STATE_AP && - wvif->beacon_int == wvif->vif->bss_conf.beacon_int) - return 0; - wfx_tx_lock_flush(wvif->wdev); - hif_reset(wvif, false); - wfx_tx_policy_init(wvif); - wvif->state = WFX_STATE_PASSIVE; - wfx_start_ap(wvif); - wfx_tx_unlock(wvif->wdev); - return 0; -} - static int wfx_upload_ap_templates(struct wfx_vif *wvif) { struct sk_buff *skb; - if (wvif->vif->type == NL80211_IFTYPE_STATION || - wvif->vif->type == NL80211_IFTYPE_MONITOR || - wvif->vif->type == NL80211_IFTYPE_UNSPECIFIED) - return 0; - skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); if (!skb) return -ENOMEM; @@ -679,52 +487,77 @@ static int wfx_upload_ap_templates(struct wfx_vif *wvif) return 0; } +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_dev *wdev = wvif->wdev; + int ret; + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_update_pm(wvif); + wvif = (struct wfx_vif *)vif->drv_priv; + wfx_upload_ap_templates(wvif); + ret = hif_start(wvif, &vif->bss_conf, wvif->channel); + if (ret > 0) + return -EIO; + return ret; +} + +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wfx_reset(wvif); +} + static void wfx_join_finalize(struct wfx_vif *wvif, struct ieee80211_bss_conf *info) { - struct ieee80211_sta *sta = NULL; - - wvif->beacon_int = info->beacon_int; - rcu_read_lock(); // protect sta - if (info->bssid && !info->ibss_joined) - sta = ieee80211_find_sta(wvif->vif, info->bssid); - if (sta) - wvif->bss_params.operational_rate_set = - wfx_rate_mask_to_hw(wvif->wdev, sta->supp_rates[wvif->channel->band]); - else - wvif->bss_params.operational_rate_set = -1; - rcu_read_unlock(); - if (sta && - info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) - hif_dual_cts_protection(wvif, true); - else - hif_dual_cts_protection(wvif, false); + wvif->join_in_progress = false; + hif_set_association_mode(wvif, info); + hif_keep_alive_period(wvif, 0); + // beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use + // the same value. + hif_set_bss_params(wvif, info->aid, 7); + hif_set_beacon_wakeup_period(wvif, 1, 1); + wfx_update_pm(wvif); +} - wfx_cqm_bssloss_sm(wvif, 0, 0, 0); - cancel_work_sync(&wvif->unjoin_work); +int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - wvif->bss_params.beacon_lost_count = 20; - wvif->bss_params.aid = info->aid; + wfx_upload_ap_templates(wvif); + wfx_do_join(wvif); + return 0; +} - hif_set_association_mode(wvif, info); +void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - if (!info->ibss_joined) { - hif_keep_alive_period(wvif, 30 /* sec */); - hif_set_bss_params(wvif, &wvif->bss_params); - hif_set_beacon_wakeup_period(wvif, info->dtim_period, - info->dtim_period); - wfx_update_pm(wvif); + wfx_reset(wvif); +} + +static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable) +{ + // Driver has Content After DTIM Beacon in queue. Driver is waiting for + // a signal from the firmware. Since we are going to stop to send + // beacons, this signal will never happens. See also + // wfx_suspend_resume_mc() + if (!enable && wfx_tx_queues_has_cab(wvif)) { + wvif->after_dtim_tx_allowed = true; + wfx_bh_request_tx(wvif->wdev); } + hif_beacon_transmit(wvif, enable); } -void wfx_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) +void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) { struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; - bool do_join = false; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; int i; mutex_lock(&wdev->conf_mutex); @@ -742,92 +575,52 @@ void wfx_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_BEACON || - changed & BSS_CHANGED_AP_PROBE_RESP || - changed & BSS_CHANGED_BSSID || - changed & BSS_CHANGED_SSID || - changed & BSS_CHANGED_IBSS) { - wvif->beacon_int = info->beacon_int; - wfx_update_beaconing(wvif); - wfx_upload_ap_templates(wvif); - wfx_fwd_probe_req(wvif, false); + if (changed & BSS_CHANGED_BASIC_RATES || + changed & BSS_CHANGED_BEACON_INT || + changed & BSS_CHANGED_BSSID) { + if (vif->type == NL80211_IFTYPE_STATION) + wfx_do_join(wvif); } - if (changed & BSS_CHANGED_BEACON_ENABLED && - wvif->state != WFX_STATE_IBSS) - hif_beacon_transmit(wvif, info->enable_beacon); + if (changed & BSS_CHANGED_AP_PROBE_RESP || + changed & BSS_CHANGED_BEACON) + wfx_upload_ap_templates(wvif); + + if (changed & BSS_CHANGED_BEACON_ENABLED) + wfx_enable_beacon(wvif, info->enable_beacon); - if (changed & BSS_CHANGED_BEACON_INFO) + if (changed & BSS_CHANGED_BEACON_INFO) { + if (vif->type != NL80211_IFTYPE_STATION) + dev_warn(wdev->dev, "%s: misunderstood change: BEACON_INFO\n", + __func__); hif_set_beacon_wakeup_period(wvif, info->dtim_period, info->dtim_period); - - /* assoc/disassoc, or maybe AID changed */ - if (changed & BSS_CHANGED_ASSOC) { - wfx_tx_lock_flush(wdev); - wvif->wep_default_key_id = -1; - wfx_tx_unlock(wdev); + // We temporary forwarded beacon for join process. It is now no + // more necessary. + wfx_filter_beacon(wvif, true); } - if (changed & BSS_CHANGED_ASSOC && !info->assoc && - (wvif->state == WFX_STATE_STA || wvif->state == WFX_STATE_IBSS)) { - /* Shedule unjoin work */ - wfx_tx_lock(wdev); - if (!schedule_work(&wvif->unjoin_work)) - wfx_tx_unlock(wdev); - } else { - if (changed & BSS_CHANGED_BEACON_INT) { - if (info->ibss_joined) - do_join = true; - else if (wvif->state == WFX_STATE_AP) - wfx_update_beaconing(wvif); - } - - if (changed & BSS_CHANGED_BSSID) - do_join = true; - - if (changed & BSS_CHANGED_ASSOC || - changed & BSS_CHANGED_BSSID || - changed & BSS_CHANGED_IBSS || - changed & BSS_CHANGED_BASIC_RATES || - changed & BSS_CHANGED_HT) { - if (info->assoc) { - if (wvif->state < WFX_STATE_PRE_STA) { - ieee80211_connection_loss(vif); - mutex_unlock(&wdev->conf_mutex); - return; - } else if (wvif->state == WFX_STATE_PRE_STA) { - wvif->state = WFX_STATE_STA; - } - } else { - do_join = true; - } - - if (info->assoc || info->ibss_joined) - wfx_join_finalize(wvif, info); - else - memset(&wvif->bss_params, 0, - sizeof(wvif->bss_params)); - } + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc || info->ibss_joined) + wfx_join_finalize(wvif, info); + else if (!info->assoc && vif->type == NL80211_IFTYPE_STATION) + wfx_reset(wvif); + else + dev_warn(wdev->dev, "%s: misunderstood change: ASSOC\n", + __func__); } - if (changed & BSS_CHANGED_ASSOC || - changed & BSS_CHANGED_ERP_CTS_PROT || - changed & BSS_CHANGED_ERP_PREAMBLE) { - u8 erp_ie[3] = { WLAN_EID_ERP_INFO, 1, 0 }; + if (changed & BSS_CHANGED_KEEP_ALIVE) + hif_keep_alive_period(wvif, info->max_idle_period * + USEC_PER_TU / USEC_PER_MSEC); + if (changed & BSS_CHANGED_ERP_CTS_PROT) hif_erp_use_protection(wvif, info->use_cts_prot); - if (info->use_cts_prot) - erp_ie[2] |= WLAN_ERP_USE_PROTECTION; - if (info->use_short_preamble) - erp_ie[2] |= WLAN_ERP_BARKER_PREAMBLE; - if (wvif->vif->type != NL80211_IFTYPE_STATION) - hif_update_ie_beacon(wvif, erp_ie, sizeof(erp_ie)); - } - if (changed & BSS_CHANGED_ASSOC || changed & BSS_CHANGED_ERP_SLOT) + if (changed & BSS_CHANGED_ERP_SLOT) hif_slot_time(wvif, info->use_short_slot ? 9 : 20); - if (changed & BSS_CHANGED_ASSOC || changed & BSS_CHANGED_CQM) + if (changed & BSS_CHANGED_CQM) hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold, info->cqm_rssi_hyst); @@ -838,31 +631,6 @@ void wfx_bss_info_changed(struct ieee80211_hw *hw, wfx_update_pm(wvif); mutex_unlock(&wdev->conf_mutex); - - if (do_join) - wfx_do_join(wvif); -} - -static void wfx_ps_notify_sta(struct wfx_vif *wvif, - enum sta_notify_cmd notify_cmd, int link_id) -{ - spin_lock_bh(&wvif->ps_state_lock); - if (notify_cmd == STA_NOTIFY_SLEEP) - wvif->sta_asleep_mask |= BIT(link_id); - else // notify_cmd == STA_NOTIFY_AWAKE - wvif->sta_asleep_mask &= ~BIT(link_id); - spin_unlock_bh(&wvif->ps_state_lock); - if (notify_cmd == STA_NOTIFY_AWAKE) - wfx_bh_request_tx(wvif->wdev); -} - -void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum sta_notify_cmd notify_cmd, struct ieee80211_sta *sta) -{ - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; - struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *) &sta->drv_priv; - - wfx_ps_notify_sta(wvif, notify_cmd, sta_priv->link_id); } static int wfx_update_tim(struct wfx_vif *wvif) @@ -873,10 +641,8 @@ static int wfx_update_tim(struct wfx_vif *wvif) skb = ieee80211_beacon_get_tim(wvif->wdev->hw, wvif->vif, &tim_offset, &tim_length); - if (!skb) { - __wfx_flush(wvif->wdev, true); + if (!skb) return -ENOENT; - } tim_ptr = skb->data + tim_offset; if (tim_offset && tim_length >= 6) { @@ -886,7 +652,7 @@ static int wfx_update_tim(struct wfx_vif *wvif) tim_ptr[2] = 0; /* Set/reset aid0 bit */ - if (wfx_tx_queues_get_after_dtim(wvif)) + if (wfx_tx_queues_has_cab(wvif)) tim_ptr[4] |= 1; else tim_ptr[4] &= ~1; @@ -917,7 +683,9 @@ int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd) { - WARN(!wfx_tx_queues_get_after_dtim(wvif), "incorrect sequence"); + if (notify_cmd != STA_NOTIFY_AWAKE) + return; + WARN(!wfx_tx_queues_has_cab(wvif), "incorrect sequence"); WARN(wvif->after_dtim_tx_allowed, "incorrect sequence"); wvif->after_dtim_tx_allowed = true; wfx_bh_request_tx(wvif->wdev); @@ -958,7 +726,7 @@ void wfx_change_chanctx(struct ieee80211_hw *hw, int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *conf) { - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; struct ieee80211_channel *ch = conf->def.chan; WARN(wvif->channel, "channel overwrite"); @@ -971,7 +739,7 @@ void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *conf) { - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; struct ieee80211_channel *ch = conf->def.chan; WARN(wvif->channel != ch, "channel mismatch"); @@ -987,7 +755,7 @@ int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { int i, ret = 0; struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_UAPSD | @@ -1021,33 +789,18 @@ int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) wvif->wdev = wdev; wvif->link_id_map = 1; // link-id 0 is reserved for multicast - spin_lock_init(&wvif->ps_state_lock); INIT_WORK(&wvif->update_tim_work, wfx_update_tim_work); - - memset(&wvif->bss_params, 0, sizeof(wvif->bss_params)); - - mutex_init(&wvif->bss_loss_lock); - INIT_DELAYED_WORK(&wvif->bss_loss_work, wfx_bss_loss_work); - - wvif->wep_default_key_id = -1; - INIT_WORK(&wvif->wep_key_work, wfx_wep_key_work); - - spin_lock_init(&wvif->event_queue_lock); - INIT_LIST_HEAD(&wvif->event_queue); - INIT_WORK(&wvif->event_handler_work, wfx_event_handler_work); + INIT_DELAYED_WORK(&wvif->beacon_loss_work, wfx_beacon_loss_work); init_completion(&wvif->set_pm_mode_complete); complete(&wvif->set_pm_mode_complete); - INIT_WORK(&wvif->update_filtering_work, wfx_update_filtering_work); - INIT_WORK(&wvif->bss_params_work, wfx_bss_params_work); - INIT_WORK(&wvif->unjoin_work, wfx_unjoin_work); + INIT_WORK(&wvif->update_pm_work, wfx_update_pm_work); INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); mutex_init(&wvif->scan_lock); init_completion(&wvif->scan_complete); INIT_WORK(&wvif->scan_work, wfx_hw_scan_work); - INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); mutex_unlock(&wdev->conf_mutex); hif_set_macaddr(wvif, vif->addr); @@ -1060,50 +813,25 @@ int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) hif_set_block_ack_policy(wvif, 0xFF, 0xFF); else hif_set_block_ack_policy(wvif, 0x00, 0x00); - // Combo force powersave mode. We can re-enable it now - ret = wfx_update_pm(wvif); } return ret; } -void wfx_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300)); mutex_lock(&wdev->conf_mutex); WARN(wvif->link_id_map != 1, "corrupted state"); - switch (wvif->state) { - case WFX_STATE_PRE_STA: - case WFX_STATE_STA: - case WFX_STATE_IBSS: - wfx_tx_lock_flush(wdev); - if (!schedule_work(&wvif->unjoin_work)) - wfx_tx_unlock(wdev); - break; - case WFX_STATE_AP: - wvif->sta_asleep_mask = 0; - /* reset.link_id = 0; */ - hif_reset(wvif, false); - break; - default: - break; - } - - wvif->state = WFX_STATE_PASSIVE; - wfx_tx_queues_wait_empty_vif(wvif); - wfx_tx_unlock(wdev); - /* FIXME: In add to reset MAC address, try to reset interface */ + hif_reset(wvif, false); hif_set_macaddr(wvif, NULL); + wfx_tx_policy_init(wvif); - wfx_cqm_bssloss_sm(wvif, 0, 0, 0); - cancel_work_sync(&wvif->unjoin_work); - wfx_free_event_queue(wvif); - + cancel_delayed_work_sync(&wvif->beacon_loss_work); wdev->vif[wvif->id] = NULL; wvif->vif = NULL; @@ -1115,8 +843,6 @@ void wfx_remove_interface(struct ieee80211_hw *hw, hif_set_block_ack_policy(wvif, 0xFF, 0xFF); else hif_set_block_ack_policy(wvif, 0x00, 0x00); - // Combo force powersave mode. We can re-enable it now - wfx_update_pm(wvif); } } @@ -1129,10 +855,5 @@ void wfx_stop(struct ieee80211_hw *hw) { struct wfx_dev *wdev = hw->priv; - wfx_tx_lock_flush(wdev); - mutex_lock(&wdev->conf_mutex); - wfx_tx_queues_clear(wdev); - mutex_unlock(&wdev->conf_mutex); - wfx_tx_unlock(wdev); - WARN(atomic_read(&wdev->tx_lock), "tx_lock is locked"); + wfx_tx_queues_check_empty(wdev); } diff --git a/drivers/staging/wfx/sta.h b/drivers/staging/wfx/sta.h index cf99a8a74a81..8a20ad9ae017 100644 --- a/drivers/staging/wfx/sta.h +++ b/drivers/staging/wfx/sta.h @@ -10,34 +10,13 @@ #include <net/mac80211.h> -#include "hif_api_cmd.h" - struct wfx_dev; struct wfx_vif; -enum wfx_state { - WFX_STATE_PASSIVE = 0, - WFX_STATE_PRE_STA, - WFX_STATE_STA, - WFX_STATE_IBSS, - WFX_STATE_AP, -}; - -struct wfx_hif_event { - struct list_head link; - struct hif_ind_event evt; -}; - -struct wfx_grp_addr_table { - bool enable; - int num_addresses; - u8 address_list[8][ETH_ALEN]; -}; - struct wfx_sta_priv { int link_id; int vif_id; - u8 buffered[IEEE80211_NUM_TIDS]; + int buffered[IEEE80211_NUM_TIDS]; // Ensure atomicity of "buffered" and calls to ieee80211_sta_set_buffered() spinlock_t lock; }; @@ -47,6 +26,8 @@ int wfx_start(struct ieee80211_hw *hw); void wfx_stop(struct ieee80211_hw *hw); int wfx_config(struct ieee80211_hw *hw, u32 changed); int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +void wfx_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int idx); u64 wfx_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list); void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, @@ -54,8 +35,10 @@ void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop); +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -82,12 +65,13 @@ void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf); // WSM Callbacks +void wfx_cooling_timeout_work(struct work_struct *work); +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd); void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd cmd); +void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi); // Other Helpers -void wfx_cqm_bssloss_sm(struct wfx_vif *wvif, int init, int good, int bad); -void wfx_update_filtering(struct wfx_vif *wvif); -int wfx_fwd_probe_req(struct wfx_vif *wvif, bool enable); +void wfx_reset(struct wfx_vif *wvif); u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates); #endif /* WFX_STA_H */ diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h index 30c6a13f0e22..0b6fbd518638 100644 --- a/drivers/staging/wfx/traces.h +++ b/drivers/staging/wfx/traces.h @@ -32,16 +32,16 @@ * xxx_name(XXX) \ * ... * - * 3. Instanciate that list_names: + * 3. Instantiate that list_names: * * list_names * - * 4. Redefine xxx_name() as a entry of array for __print_symbolic() + * 4. Redefine xxx_name() as an entry of array for __print_symbolic() * * #undef xxx_name * #define xxx_name(msg) { msg, #msg }, * - * 5. list_name can now nearlu be used with __print_symbolic() but, + * 5. list_name can now nearly be used with __print_symbolic() but, * __print_symbolic() dislike last comma of list. So we define a new list * with a dummy element: * @@ -104,8 +104,10 @@ hif_msg_list_enum hif_mib_name(ARP_KEEP_ALIVE_PERIOD) \ hif_mib_name(BEACON_FILTER_ENABLE) \ hif_mib_name(BEACON_FILTER_TABLE) \ + hif_mib_name(BEACON_STATS) \ hif_mib_name(BEACON_WAKEUP_PERIOD) \ hif_mib_name(BLOCK_ACK_POLICY) \ + hif_mib_name(CCA_CONFIG) \ hif_mib_name(CONFIG_DATA_FILTER) \ hif_mib_name(COUNTERS_TABLE) \ hif_mib_name(CURRENT_TX_POWER_LEVEL) \ @@ -114,29 +116,32 @@ hif_msg_list_enum hif_mib_name(DOT11_MAX_TRANSMIT_MSDU_LIFETIME) \ hif_mib_name(DOT11_RTS_THRESHOLD) \ hif_mib_name(DOT11_WEP_DEFAULT_KEY_ID) \ + hif_mib_name(ETHERTYPE_DATAFRAME_CONDITION) \ + hif_mib_name(EXTENDED_COUNTERS_TABLE) \ hif_mib_name(GL_BLOCK_ACK_INFO) \ hif_mib_name(GL_OPERATIONAL_POWER_MODE) \ hif_mib_name(GL_SET_MULTI_MSG) \ + hif_mib_name(GRP_SEQ_COUNTER) \ hif_mib_name(INACTIVITY_TIMER) \ hif_mib_name(INTERFACE_PROTECTION) \ hif_mib_name(IPV4_ADDR_DATAFRAME_CONDITION) \ hif_mib_name(IPV6_ADDR_DATAFRAME_CONDITION) \ hif_mib_name(KEEP_ALIVE_PERIOD) \ hif_mib_name(MAC_ADDR_DATAFRAME_CONDITION) \ + hif_mib_name(MAGIC_DATAFRAME_CONDITION) \ + hif_mib_name(MAX_TX_POWER_LEVEL) \ hif_mib_name(NON_ERP_PROTECTION) \ hif_mib_name(NS_IP_ADDRESSES_TABLE) \ hif_mib_name(OVERRIDE_INTERNAL_TX_RATE) \ + hif_mib_name(PORT_DATAFRAME_CONDITION) \ hif_mib_name(PROTECTED_MGMT_POLICY) \ - hif_mib_name(RX_FILTER) \ hif_mib_name(RCPI_RSSI_THRESHOLD) \ + hif_mib_name(RX_FILTER) \ hif_mib_name(SET_ASSOCIATION_MODE) \ hif_mib_name(SET_DATA_FILTERING) \ - hif_mib_name(ETHERTYPE_DATAFRAME_CONDITION) \ hif_mib_name(SET_HT_PROTECTION) \ - hif_mib_name(MAGIC_DATAFRAME_CONDITION) \ hif_mib_name(SET_TX_RATE_RETRY_POLICY) \ hif_mib_name(SET_UAPSD_INFORMATION) \ - hif_mib_name(PORT_DATAFRAME_CONDITION) \ hif_mib_name(SLOT_TIME) \ hif_mib_name(STATISTICS_TABLE) \ hif_mib_name(TEMPLATE_FRAME) \ @@ -169,7 +174,7 @@ DECLARE_EVENT_CLASS(hif_data, int header_len; __entry->tx_fill_level = tx_fill_level; - __entry->msg_len = hif->len; + __entry->msg_len = le16_to_cpu(hif->len); __entry->msg_id = hif->id; __entry->if_id = hif->interface; if (is_recv) @@ -179,7 +184,7 @@ DECLARE_EVENT_CLASS(hif_data, if (!is_recv && (__entry->msg_id == HIF_REQ_ID_READ_MIB || __entry->msg_id == HIF_REQ_ID_WRITE_MIB)) { - __entry->mib = le16_to_cpup((u16 *) hif->body); + __entry->mib = le16_to_cpup((__le16 *)hif->body); header_len = 4; } else { __entry->mib = -1; @@ -193,8 +198,8 @@ DECLARE_EVENT_CLASS(hif_data, TP_printk("%d:%d:%s_%s%s%s: %s%s (%d bytes)", __entry->tx_fill_level, __entry->if_id, - __print_symbolic(__entry->msg_id, hif_msg_list), __entry->msg_type, + __print_symbolic(__entry->msg_id, hif_msg_list), __entry->mib != -1 ? "/" : "", __entry->mib != -1 ? __print_symbolic(__entry->mib, hif_mib_list) : "", __print_hex(__entry->buf, __entry->buf_len), @@ -382,8 +387,8 @@ TRACE_EVENT(tx_stats, int i; __entry->pkt_id = tx_cnf->packet_id; - __entry->delay_media = tx_cnf->media_delay; - __entry->delay_queue = tx_cnf->tx_queue_delay; + __entry->delay_media = le32_to_cpu(tx_cnf->media_delay); + __entry->delay_queue = le32_to_cpu(tx_cnf->tx_queue_delay); __entry->delay_fw = delay; __entry->ack_failures = tx_cnf->ack_failures; if (!tx_cnf->status || __entry->ack_failures) @@ -409,7 +414,7 @@ TRACE_EVENT(tx_stats, __entry->flags |= 0x10; if (tx_cnf->status) __entry->flags |= 0x20; - if (tx_cnf->status == HIF_REQUEUE) + if (tx_cnf->status == HIF_STATUS_TX_FAIL_REQUEUE) __entry->flags |= 0x40; ), TP_printk("packet ID: %08x, rate policy: %s %d|%d %d|%d %d|%d %d|%d -> %d attempt, Delays media/queue/total: %4dus/%4dus/%4dus", diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h index 8b85bb1abb9c..73e216733ce4 100644 --- a/drivers/staging/wfx/wfx.h +++ b/drivers/staging/wfx/wfx.h @@ -21,10 +21,7 @@ #include "main.h" #include "queue.h" #include "secure_link.h" -#include "sta.h" -#include "scan.h" #include "hif_tx.h" -#include "hif_api_general.h" #define USEC_PER_TXOP 32 // see struct ieee80211_tx_queue_params #define USEC_PER_TU 1024 @@ -45,21 +42,24 @@ struct wfx_dev { struct hif_ind_startup hw_caps; struct wfx_hif hif; struct sl_context sl; - int chip_frozen; + struct delayed_work cooling_timeout_work; + bool poll_irq; + bool chip_frozen; struct mutex conf_mutex; struct wfx_hif_cmd hif_cmd; struct wfx_queue tx_queue[4]; - struct wfx_queue_stats tx_queue_stats; - int tx_burst_idx; + struct sk_buff_head tx_pending; + wait_queue_head_t tx_dequeue; atomic_t tx_lock; atomic_t packet_id; u32 key_map; - struct hif_req_add_key keys[MAX_KEY_ENTRIES]; struct hif_rx_stats rx_stats; struct mutex rx_stats_lock; + struct hif_tx_power_loop_info tx_power_loop_info; + struct mutex tx_power_loop_info_lock; }; struct wfx_vif { @@ -67,42 +67,23 @@ struct wfx_vif { struct ieee80211_vif *vif; struct ieee80211_channel *channel; int id; - enum wfx_state state; - - int bss_loss_state; - u32 bss_loss_confirm_id; - struct mutex bss_loss_lock; - struct delayed_work bss_loss_work; u32 link_id_map; bool after_dtim_tx_allowed; - struct wfx_grp_addr_table mcast_filter; + bool join_in_progress; - s8 wep_default_key_id; - struct sk_buff *wep_pending_skb; - struct work_struct wep_key_work; + struct delayed_work beacon_loss_work; struct tx_policy_cache tx_policy_cache; struct work_struct tx_policy_upload_work; - u32 sta_asleep_mask; - spinlock_t ps_state_lock; struct work_struct update_tim_work; - int beacon_int; - bool filter_bssid; - bool fwd_probe_req; - bool disable_beacon_filter; - struct work_struct update_filtering_work; + int filter_mcast_count; + u8 filter_mcast_addr[8][ETH_ALEN]; unsigned long uapsd_mask; - struct ieee80211_tx_queue_params edca_params[IEEE80211_NUM_ACS]; - struct hif_req_set_bss_params bss_params; - struct work_struct bss_params_work; - - int join_complete_status; - struct work_struct unjoin_work; /* avoid some operations in parallel with scan */ struct mutex scan_lock; @@ -111,11 +92,9 @@ struct wfx_vif { bool scan_abort; struct ieee80211_scan_request *scan_req; + bool bss_not_support_ps_poll; + struct work_struct update_pm_work; struct completion set_pm_mode_complete; - - struct list_head event_queue; - spinlock_t event_queue_lock; - struct work_struct event_handler_work; }; static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id) |