All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Kazior <michal.kazior@tieto.com>
To: Benjamin Berg <benjamin@sipsolutions.net>
Cc: Kalle Valo <kvalo@qca.qualcomm.com>,
	linux-wireless <linux-wireless@vger.kernel.org>,
	"ath10k@lists.infradead.org" <ath10k@lists.infradead.org>,
	Sebastian Gottschall <s.gottschall@dd-wrt.com>,
	Simon Wunderlich <sw@simonwunderlich.de>,
	Mathias Kretschmer <mathias.kretschmer@fit.fraunhofer.de>
Subject: Re: [PATCH] ath10k: Allow setting coverage class
Date: Wed, 27 Jul 2016 11:15:11 +0200	[thread overview]
Message-ID: <CA+BoTQmLdfLaANVBqoSW8WQwZSSNz0WrJNvA0fji4i9XOd1D9w@mail.gmail.com> (raw)
In-Reply-To: <1469608424-11370-1-git-send-email-benjamin@sipsolutions.net>

On 27 July 2016 at 10:33, Benjamin Berg <benjamin@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ł

WARNING: multiple messages have this Message-ID (diff)
From: Michal Kazior <michal.kazior@tieto.com>
To: Benjamin Berg <benjamin@sipsolutions.net>
Cc: Simon Wunderlich <sw@simonwunderlich.de>,
	linux-wireless <linux-wireless@vger.kernel.org>,
	Sebastian Gottschall <s.gottschall@dd-wrt.com>,
	Kalle Valo <kvalo@qca.qualcomm.com>,
	"ath10k@lists.infradead.org" <ath10k@lists.infradead.org>,
	Mathias Kretschmer <mathias.kretschmer@fit.fraunhofer.de>
Subject: Re: [PATCH] ath10k: Allow setting coverage class
Date: Wed, 27 Jul 2016 11:15:11 +0200	[thread overview]
Message-ID: <CA+BoTQmLdfLaANVBqoSW8WQwZSSNz0WrJNvA0fji4i9XOd1D9w@mail.gmail.com> (raw)
In-Reply-To: <1469608424-11370-1-git-send-email-benjamin@sipsolutions.net>

On 27 July 2016 at 10:33, Benjamin Berg <benjamin@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ł

_______________________________________________
ath10k mailing list
ath10k@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/ath10k

  reply	other threads:[~2016-07-27  9:15 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-27  8:33 [PATCH] ath10k: Allow setting coverage class Benjamin Berg
2016-07-27  8:33 ` Benjamin Berg
2016-07-27  9:15 ` Michal Kazior [this message]
2016-07-27  9:15   ` Michal Kazior
2016-07-27 10:28 ` kbuild test robot
2016-07-27 10:28   ` kbuild test robot
2016-07-27 17:26 ` Ben Greear
2016-07-27 17:26   ` Ben Greear
2016-07-29 14:52   ` Benjamin Berg
2016-07-29 14:52     ` Benjamin Berg
2016-07-29 15:09     ` Ben Greear
2016-07-29 15:09       ` Ben Greear
2016-07-29 16:38       ` Sebastian Gottschall
2016-07-29 16:38         ` Sebastian Gottschall
2016-08-03  7:09       ` Michal Kazior
2016-08-03  7:09         ` Michal Kazior

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CA+BoTQmLdfLaANVBqoSW8WQwZSSNz0WrJNvA0fji4i9XOd1D9w@mail.gmail.com \
    --to=michal.kazior@tieto.com \
    --cc=ath10k@lists.infradead.org \
    --cc=benjamin@sipsolutions.net \
    --cc=kvalo@qca.qualcomm.com \
    --cc=linux-wireless@vger.kernel.org \
    --cc=mathias.kretschmer@fit.fraunhofer.de \
    --cc=s.gottschall@dd-wrt.com \
    --cc=sw@simonwunderlich.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.