[PATCH] ath10k: Allow setting coverage class

Michal Kazior michal.kazior at tieto.com
Wed Jul 27 02:15:11 PDT 2016


On 27 July 2016 at 10:33, Benjamin Berg <benjamin at sipsolutions.net> wrote:
> Unfortunately ath10k does not generally allow modifying the coverage class
> with the stock firmware and Qualcomm has so far refused to implement this
> feature so that it can be properly supported in ath10k. If we however know
> the registers that need to be modified for proper operation with a higher
> coverage class, then we can do these modifications from the driver.
>
> This patch implements this hack for first generation cards which are based
> on a core that is similar to ath9k. The registers are modified in place and
> need to be re-written every time the firmware sets them. To achieve this
> the register status is verified after any event from the firmware.

"After any event from firmware" would also need to include HTT events
which your patch doesn't consider.


> The coverage class may not be modified temporarily right after the card
> re-initializes the registers. This is for example the case during scanning.
>
> A warning will be generated if the hack is not supported on the card or
> unexpected values are hit. There is no error reporting for userspace
> applications though (this is a limitation in the mac80211 driver
> interface).

With a recent change in ath10k the ieee80211_ops can be updated in
ar->ops so you can NULL-ify .set_coverage_class before registering to
mac80211. See how wake_tx_queue() is masked. You could use this to
mask it for WAVE2 devices that haven't been verified.


[...]
> @@ -257,6 +258,12 @@ extern const struct ath10k_hw_regs qca6174_regs;
>  extern const struct ath10k_hw_regs qca99x0_regs;
>  extern const struct ath10k_hw_regs qca4019_regs;
>
> +enum ath10k_hw_mac_core_rev {
> +       ATH10K_HW_MAC_CORE_UNKNOWN = 0,
> +       ATH10K_HW_MAC_CORE_ATH9K,

WAVE1 would be more appropriate.


> +       ATH10K_HW_MAC_CORE_WAVE2,
> +};
> +
[...]
> +#define ATH9K_MAC_TIME_OUT             0x8014
> +#define ATH9K_MAC_TIME_OUT_MAX         0x00003FFF
> +#define ATH9K_MAC_TIME_OUT_ACK         0x00003FFF
> +#define ATH9K_MAC_TIME_OUT_ACK_S       0
> +#define ATH9K_MAC_TIME_OUT_CTS         0x3FFF0000
> +#define ATH9K_MAC_TIME_OUT_CTS_S       16
> +
> +#define ATH9K_MAC_IFS_SLOT             0x1070
> +#define ATH9K_MAC_IFS_SLOT_M           0x0000FFFF
> +#define ATH9K_MAC_IFS_SLOT_RESV0       0xFFFF0000

The prefix is wrong. It shouldn't be ATH9K.

Moreover FW refers to these register as PCU_ACK_CTS_TIMEOUT and
PCU_GBL_IFS_SLOT.


> +
>  #endif /* _HW_H_ */
> diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
> index 55c823f..a9b587e 100644
> --- a/drivers/net/wireless/ath/ath10k/mac.c
> +++ b/drivers/net/wireless/ath/ath10k/mac.c
> @@ -5372,6 +5372,15 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
>         mutex_unlock(&ar->conf_mutex);
>  }
>
> +static void ath10k_set_coverage_class(struct ieee80211_hw *hw,
> +                                     s16 value)

Wrong function prefix/name. Should be: ath10k_mac_op_set_coverage_class


> +{
> +       struct ath10k *ar = hw->priv;
> +
> +       if (ath10k_wmi_pdev_set_coverage_class(ar, value) == -EOPNOTSUPP)
> +               ath10k_warn(ar, "Modification of coverage class is not supported!\n");

Warning doesn't match the style used in ath10k. "failed to set
coverage class: not supported\n".


[...]
> diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
> index 64ebd30..3ebc57e 100644
> --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
> +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
> @@ -52,6 +52,8 @@ struct wmi_ops {
>         int (*pull_wow_event)(struct ath10k *ar, struct sk_buff *skb,
>                               struct wmi_wow_ev_arg *arg);
>         enum wmi_txbf_conf (*get_txbf_conf_scheme)(struct ath10k *ar);
> +       void (*set_pdev_coverage_class)(struct ath10k *ar,
> +                                       s16 value);

WMI ops are used to generate and process events and command buffers.
These ops are not supposed to have side-effects but
"set_pdev_coverage_class" implies it does.


[...]
>  /* MAIN WMI cmd track */
>  static struct wmi_cmd_map wmi_cmd_map = {
> @@ -3096,6 +3097,121 @@ ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb,
>         return 0;
>  }
>
> +static void
> +ath10k_ath9k_set_pdev_coverage_class(struct ath10k *ar, s16 value)

The prefix is wrong. "ath9k" should be used here.

ath10k_wmi_ is appropriate for stuff in wmi.c


[...]
> +       /* Do some sanity checks on the slottime register. */
> +       if (unlikely(slottime_reg % counters_freq_mhz)) {
> +               ath10k_warn(ar,
> +                           "Not adjusting coverage class timeouts, expected an integer microsecond slot time in HW register\n");

Wrong message style.


> +
> +               goto store_regs;
> +       }
> +
> +       slottime = (slottime_reg & ATH9K_MAC_IFS_SLOT_M) / counters_freq_mhz;
> +       if (unlikely(slottime != 9 && slottime != 20)) {
> +               ath10k_warn(ar,
> +                           "Not adjusting coverage class timeouts, expected a slot time of 9 or 20us in HW register. It is %uus.\n",
> +                           slottime);

Wrong message style.


[...]
> +       timeout_reg = (timeout_reg & ~ATH9K_MAC_TIME_OUT_ACK) | timeout;
> +
> +       /* Update cts timeout (upper halfword). */
> +       timeout = (timeout_reg & ATH9K_MAC_TIME_OUT_CTS)
> +       timeout = timeout >> ATH9K_MAC_TIME_OUT_CTS_S;
> +       timeout += 3 * value * counters_freq_mhz;
> +       timeout = min_t(u32, timeout, ATH9K_MAC_TIME_OUT_MAX);
> +       timeout = (timeout << ATH9K_MAC_TIME_OUT_CTS_S)
> +       timeout = timeout & ATH9K_MAC_TIME_OUT_CTS;
> +       timeout_reg = (timeout_reg & ~ATH9K_MAC_TIME_OUT_CTS) | timeout;

I would really love to see Jakub's hw register helper macros get
merged and used here..


> +
> +       ath10k_hif_write32(ar, WLAN_MAC_BASE_ADDRESS + 0x1070, slottime_reg);
> +       ath10k_hif_write32(ar, WLAN_MAC_BASE_ADDRESS + 0x8014, timeout_reg);

So you're defining register offsets and then you're using literal
values to address them?..


[...]
> +static void
> +ath10k_wmi_op_set_pdev_coverage_class(struct ath10k *ar, s16 value)
> +{
> +       switch (ar->hw_values->mac_core_rev) {
> +       case ATH10K_HW_MAC_CORE_ATH9K:
> +               ath10k_ath9k_set_pdev_coverage_class(ar, value);
> +               break;
> +       default:
> +               if (value != -1)
> +                       ath10k_warn(ar, "Setting the coverage class is not supported for this chipset.");
> +               break;
> +       }
> +}

This is wrong in general. You aren't using WMI to submit coverage
class configuration so it doesn't belong here (wmi.c and wmi-ops).
You're poking HW registers directly actually.

The logic should be placed in mac.c and hw.c and abstracted away
through hw_ops which are defined/populated per-hw in pci.c. Vasanth
recently worked on something similar for rx descriptor handling
(ar->hw_rx_desc_ops). I think it should be generalized to hw_ops and
you should add the coverage-class stuff on top of that.


Michał



More information about the ath10k mailing list