* Re: [PATCH V2] mac80211: Ignore VHT IE from peer with wrong rx_mcs_map
From: Johannes Berg @ 2016-11-15 13:20 UTC (permalink / raw)
To: Filip Matusiak, linux-wireless
Cc: marek.kwaczynski, davem, netdev, linux-kernel
In-Reply-To: <1478077466-4308-1-git-send-email-filip.matusiak@tieto.com>
On Wed, 2016-11-02 at 10:04 +0100, Filip Matusiak wrote:
> This is a workaround for VHT-enabled STAs which break the spec
> and have the VHT-MCS Rx map filled in with value 3 for all eight
> spacial streams, an example is AR9462 in AP mode.
>
> As per spec, in section 22.1.1 Introduction to the VHT PHY
> A VHT STA shall support at least single spactial stream VHT-MCSs
> 0 to 7 (transmit and receive) in all supported channel widths.
>
> Some devices in STA mode will get firmware assert when trying to
> associate, examples are QCA9377 & QCA6174.
>
> Packet example of broken VHT Cap IE of AR9462:
>
> [...]
Applied, thanks.
johannes
^ permalink raw reply
* [PATCH v7] mwifiex: parse device tree node for PCIe
From: Amitkumar Karwar @ 2016-11-15 13:14 UTC (permalink / raw)
To: linux-wireless
Cc: Cathy Luo, Nishant Sarmukadam, rajatja, briannorris,
dmitry.torokhov, Xinming Hu, Amitkumar Karwar
From: Xinming Hu <huxm@marvell.com>
This patch derives device tree node from pcie bus layer framework.
Device tree bindings file has been renamed(marvell-sd8xxx.txt ->
marvell-8xxx.txt) to accommodate PCIe changes.
Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: Rajat Jain <rajatja@google.com>
Reviewed-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
---
v2: Included vendor and product IDs in compatible strings for PCIe
chipsets(Rob Herring)
v3: Patch is created using -M option so that it will only include diff of
original and renamed files(Rob Herring)
Resend v3: Resending the patch because I missed to include device tree mailing
while sending v3.
v4: Fix error handling, also move-on even if no device tree node is present.
v5: Update commit log to include memory leak, return -EINVAL instead of -1.
v6: Remove an unnecessary error print, fix typo in commit log
v7: a) Earlier versions of this patch claims to have a change which fixes "memory
leak". But it actually introduces double-free problem. That change is removed
here(Brian Norris)
b) Cosmetic change in bindings documentation(Rob Herring)
s/marvell/Marvell/
s/sdio\/pcie/SDIO\/PCIE/
---
.../{marvell-sd8xxx.txt => marvell-8xxx.txt} | 8 +++++---
drivers/net/wireless/marvell/mwifiex/pcie.c | 24 ++++++++++++++++++++++
drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 3 ++-
3 files changed, 31 insertions(+), 4 deletions(-)
rename Documentation/devicetree/bindings/net/wireless/{marvell-sd8xxx.txt => marvell-8xxx.txt} (91%)
diff --git a/Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt b/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
similarity index 91%
rename from Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt
rename to Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
index c421aba..980b16df 100644
--- a/Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt
+++ b/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
@@ -1,8 +1,8 @@
-Marvell 8897/8997 (sd8897/sd8997) SDIO devices
+Marvell 8897/8997 (sd8897/sd8997/pcie8997) SDIO/PCIE devices
------
-This node provides properties for controlling the marvell sdio wireless device.
-The node is expected to be specified as a child node to the SDIO controller that
+This node provides properties for controlling the Marvell SDIO/PCIE wireless device.
+The node is expected to be specified as a child node to the SDIO/PCIE controller that
connects the device to the system.
Required properties:
@@ -10,6 +10,8 @@ Required properties:
- compatible : should be one of the following:
* "marvell,sd8897"
* "marvell,sd8997"
+ * "pci11ab,2b42"
+ * "pci1b4b,2b42"
Optional properties:
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 063c707..83a41b5 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -37,6 +37,22 @@
static struct semaphore add_remove_card_sem;
+static const struct of_device_id mwifiex_pcie_of_match_table[] = {
+ { .compatible = "pci11ab,2b42" },
+ { .compatible = "pci1b4b,2b42" },
+ { }
+};
+
+static int mwifiex_pcie_probe_of(struct device *dev)
+{
+ if (!of_match_node(mwifiex_pcie_of_match_table, dev->of_node)) {
+ dev_err(dev, "required compatible string missing\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int
mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
size_t size, int flags)
@@ -185,6 +201,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct pcie_service_card *card;
+ int ret;
pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
pdev->vendor, pdev->device, pdev->revision);
@@ -206,6 +223,13 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
card->pcie.can_ext_scan = data->can_ext_scan;
}
+ /* device tree node parsing and platform specific configuration*/
+ if (pdev->dev.of_node) {
+ ret = mwifiex_pcie_probe_of(&pdev->dev);
+ if (ret)
+ return ret;
+ }
+
if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
MWIFIEX_PCIE)) {
pr_err("%s failed\n", __func__);
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
index 0a54e21..b697b61 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
@@ -2235,7 +2235,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
* The cal-data can be read from device tree and/or
* a configuration file and downloaded to firmware.
*/
- if (priv->adapter->iface_type == MWIFIEX_SDIO &&
+ if ((priv->adapter->iface_type == MWIFIEX_SDIO ||
+ priv->adapter->iface_type == MWIFIEX_PCIE) &&
adapter->dev->of_node) {
adapter->dt_node = adapter->dev->of_node;
if (of_property_read_u32(adapter->dt_node,
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] broadcom/brcm80211/brcmfmac/cfg80211 driver, bad regulatory domain frequency value
From: Gianfranco Costamagna @ 2016-11-15 13:13 UTC (permalink / raw)
To: Kalle Valo
Cc: Arend Van Spriel, brcm80211-dev-list@broadcom.com,
linux-wireless@vger.kernel.org, nsmaldone@tierratelematics.com,
Marco.Arlone@roj.com
In-Reply-To: <87r36dov6u.fsf@purkki.adurom.net>
Hi,
> Signed-off-by: Nicola Smaldone <nicola.smaldone@tierraservice.com>
> Signed-off-by: Arlone Marco <marco.arlone@roj.com>
>Please note that you cannot add Signed-off-by for other people without
>their explicit approval (see Documentation/SubmittingPatches). I don't
>know if they did it in this case or not, but wanted to point out this
>anyway.
The first signoff is myself, with the company email, the other two signoffs
are from: the author, and Nicola, who did work with me to test it
(even if a typo fix is not "testable").
Nicola, Marco, is it ok to add your two names in the signoff part?
(that was a verbal talk, I don't have anything written)
Gianfranco
^ permalink raw reply
* Re: [PATCH] broadcom/brcm80211/brcmfmac/cfg80211 driver, bad regulatory domain frequency value
From: Kalle Valo @ 2016-11-15 11:10 UTC (permalink / raw)
To: Gianfranco Costamagna
Cc: Arend Van Spriel, brcm80211-dev-list@broadcom.com,
linux-wireless@vger.kernel.org, nsmaldone@tierratelematics.com,
Marco.Arlone@roj.com
In-Reply-To: <810879191.6335567.1479124065921@mail.yahoo.com>
Gianfranco Costamagna <locutusofborg@debian.org> writes:
>> Well, not before you pointed it out ;-). You are welcome to send a patch
>> fixing it. Otherwise, I will take care of it.
>
> attaching a format-patch like version.
> I don't think we need a Tested-by or whatever, because it is just a typo in a comment.
> (this is my first contribution, feel free to rebase or change whatever you prefer
> to make it in line with other styles)
>
> (I gave authorship to Marco, the first one who discovered such typo)
[...]
> Signed-off-by: Gianfranco Costamagna <gianfranco.costamagna@abinsula.com>
> Signed-off-by: Nicola Smaldone <nicola.smaldone@tierraservice.com>
> Signed-off-by: Arlone Marco <marco.arlone@roj.com>
Please note that you cannot add Signed-off-by for other people without
their explicit approval (see Documentation/SubmittingPatches). I don't
know if they did it in this case or not, but wanted to point out this
anyway.
--
Kalle Valo
^ permalink raw reply
* [PATCH] cfg80211: limit scan results cache size
From: Johannes Berg @ 2016-11-15 11:05 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
It's possible to make scanning consume almost arbitrary amounts
of memory, e.g. by sending beacon frames with random BSSIDs at
high rates while somebody is scanning.
Limit the number of BSS table entries we're willing to cache to
1000, limiting maximum memory usage to maybe 4-5MB, but lower
in practice - that would be the case for having both full-sized
beacon and probe response frames for each entry; this seems not
possible in practice, so a limit of 1000 entries will likely be
closer to 0.5 MB.
Cc: stable@vger.kernel.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/wireless/core.h | 1 +
net/wireless/scan.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 08d2e948c9ad..f0c0c8a48c92 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -71,6 +71,7 @@ struct cfg80211_registered_device {
struct list_head bss_list;
struct rb_root bss_tree;
u32 bss_generation;
+ u32 bss_entries;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
struct sk_buff *scan_msg;
struct cfg80211_sched_scan_request __rcu *sched_scan_req;
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index b5bd58d0f731..35ad69fd0838 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -57,6 +57,19 @@
* also linked into the probe response struct.
*/
+/*
+ * Limit the number of BSS entries stored in mac80211. Each one is
+ * a bit over 4k at most, so this limits to roughly 4-5M of memory.
+ * If somebody wants to really attack this though, they'd likely
+ * use small beacons, and only one type of frame, limiting each of
+ * the entries to a much smaller size (in order to generate more
+ * entries in total, so overhead is bigger.)
+ */
+static int bss_entries_limit = 1000;
+module_param(bss_entries_limit, int, 0644);
+MODULE_PARM_DESC(bss_entries_limit,
+ "limit to number of scan BSS entries (per wiphy, default 1000)");
+
#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
static void bss_free(struct cfg80211_internal_bss *bss)
@@ -137,6 +150,10 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
list_del_init(&bss->list);
rb_erase(&bss->rbn, &rdev->bss_tree);
+ rdev->bss_entries--;
+ WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
+ "rdev bss entries[%d]/list[empty:%d] corruption\n",
+ rdev->bss_entries, list_empty(&rdev->bss_list));
bss_ref_put(rdev, bss);
return true;
}
@@ -163,6 +180,40 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
rdev->bss_generation++;
}
+static bool cfg80211_bss_expire_oldest(struct cfg80211_registered_device *rdev)
+{
+ struct cfg80211_internal_bss *bss, *oldest = NULL;
+ bool ret;
+
+ lockdep_assert_held(&rdev->bss_lock);
+
+ list_for_each_entry(bss, &rdev->bss_list, list) {
+ if (atomic_read(&bss->hold))
+ continue;
+
+ if (!list_empty(&bss->hidden_list) &&
+ !bss->pub.hidden_beacon_bss)
+ continue;
+
+ if (oldest && time_before(oldest->ts, bss->ts))
+ continue;
+ oldest = bss;
+ }
+
+ if (WARN_ON(!oldest))
+ return false;
+
+ /*
+ * The callers make sure to increase rdev->bss_generation if anything
+ * gets removed (and a new entry added), so there's no need to also do
+ * it here.
+ */
+
+ ret = __cfg80211_unlink_bss(rdev, oldest);
+ WARN_ON(!ret);
+ return ret;
+}
+
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
bool send_message)
{
@@ -689,6 +740,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
const u8 *ie;
int i, ssidlen;
u8 fold = 0;
+ u32 n_entries = 0;
ies = rcu_access_pointer(new->pub.beacon_ies);
if (WARN_ON(!ies))
@@ -712,6 +764,12 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
/* This is the bad part ... */
list_for_each_entry(bss, &rdev->bss_list, list) {
+ /*
+ * we're iterating all the entries anyway, so take the
+ * opportunity to validate the list length accounting
+ */
+ n_entries++;
+
if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
continue;
if (bss->pub.channel != new->pub.channel)
@@ -740,6 +798,10 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
new->pub.beacon_ies);
}
+ WARN_ONCE(n_entries != rdev->bss_entries,
+ "rdev bss entries[%d]/list[len:%d] corruption\n",
+ rdev->bss_entries, n_entries);
+
return true;
}
@@ -894,7 +956,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
}
}
+ if (rdev->bss_entries >= bss_entries_limit &&
+ !cfg80211_bss_expire_oldest(rdev)) {
+ kfree(new);
+ goto drop;
+ }
+
list_add_tail(&new->list, &rdev->bss_list);
+ rdev->bss_entries++;
rb_insert_bss(rdev, new);
found = new;
}
--
2.9.3
^ permalink raw reply related
* Re: [RFC 10/12] ath10k: Added QCA65XX hw definition
From: Valo, Kalle @ 2016-11-15 10:54 UTC (permalink / raw)
To: michal.kazior@tieto.com
Cc: Erik Stromdahl, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <CA+BoTQmcyVQDOd2o0YDvepuLbSz76p8hetrWA6mWJeGxvbM8iQ@mail.gmail.com>
Michal Kazior <michal.kazior@tieto.com> writes:
> On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> w=
rote:
>> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
>> ---
>> drivers/net/wireless/ath/ath10k/hw.h | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless=
/ath/ath10k/hw.h
>> index 46142e9..ef45ecf 100644
>> --- a/drivers/net/wireless/ath/ath10k/hw.h
>> +++ b/drivers/net/wireless/ath/ath10k/hw.h
>> @@ -224,6 +224,7 @@ enum ath10k_hw_rev {
>> ATH10K_HW_QCA9377,
>> ATH10K_HW_QCA4019,
>> ATH10K_HW_QCA9887,
>> + ATH10K_HW_QCA65XX,
>
> Are you 100% positive that you're supporting all QCA65XX chips? The
> rule of thumb is to avoid Xs as much as possible unless totally
> perfectly completely sure.
But the thing is that nobody can't be absolutely sure as we never know
what marketing comes up within few years again. So I would say that XX
in chip names should be completely avoided to avoid any confusion. We
already suffer from this in ath10k with QCA988X and QCA9888 which are
different designs but the names overlap.
I haven't reviewed Erik's patches yet but I'm surprised why even a new
enum value is needed here. I was assuming we could use ATH10K_HW_QCA6174
because AFAIK they share the same design. Any particular reason for
this?
--=20
Kalle Valo=
^ permalink raw reply
* Re: [RFC 09/12] ath10k: Mailbox address definitions
From: Valo, Kalle @ 2016-11-15 10:48 UTC (permalink / raw)
To: michal.kazior@tieto.com
Cc: Erik Stromdahl, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <CA+BoTQnohNffDOt_mYRuATv9wBAvOy=t6hGdS9MVRkZuwRE1nA@mail.gmail.com>
Michal Kazior <michal.kazior@tieto.com> writes:
> On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> w=
rote:
>> Address definitions for SDIO/mbox based chipsets.
>>
>> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
>> ---
>> drivers/net/wireless/ath/ath10k/hw.h | 53 +++++++++++++++++++++++++++=
+++++++
>> 1 file changed, 53 insertions(+)
>>
>> diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless=
/ath/ath10k/hw.h
>> index 883547f..46142e9 100644
>> --- a/drivers/net/wireless/ath/ath10k/hw.h
>> +++ b/drivers/net/wireless/ath/ath10k/hw.h
>> @@ -814,6 +814,59 @@ struct ath10k_hw_ops {
>> #define QCA9887_EEPROM_ADDR_LO_MASK 0x00ff0000
>> #define QCA9887_EEPROM_ADDR_LO_LSB 16
>>
>> +#define MBOX_RESET_CONTROL_ADDRESS 0x00000000
>> +#define MBOX_HOST_INT_STATUS_ADDRESS 0x00000800
>> +#define MBOX_HOST_INT_STATUS_ERROR_LSB 7
>> +#define MBOX_HOST_INT_STATUS_ERROR_MASK 0x00000080
>
> I would again suggest using Jakub's bitfield GET_FIELD stuff to get
> rid of MASK+LSB and just have single define per register field. Kalle,
> thoughts?
Same comment as with the other patch, very much preferred but not a hard
requirement.
--=20
Kalle Valo=
^ permalink raw reply
* Re: [RFC 05/12] ath10k: htc: Added ATH10K_HTC_FLAG_BUNDLE_LSB
From: Valo, Kalle @ 2016-11-15 10:46 UTC (permalink / raw)
To: michal.kazior@tieto.com
Cc: Erik Stromdahl, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <CA+BoTQmcB7+aH3wvG-mRSdBS8VaJ1OrLYQ0HCbCJeoH9ccxXNQ@mail.gmail.com>
Michal Kazior <michal.kazior@tieto.com> writes:
> On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> w=
rote:
>> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
>> ---
>> drivers/net/wireless/ath/ath10k/htc.h | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireles=
s/ath/ath10k/htc.h
>> index 589800a..df16a04 100644
>> --- a/drivers/net/wireless/ath/ath10k/htc.h
>> +++ b/drivers/net/wireless/ath/ath10k/htc.h
>> @@ -62,6 +62,8 @@ enum ath10k_htc_rx_flags {
>> ATH10K_HTC_FLAG_BUNDLE_MASK =3D 0xF0
>> };
>>
>> +#define ATH10K_HTC_FLAG_BUNDLE_LSB 4
>
> Just an idea - we could start using FIELD_GET() with
> ATH10K_HTC_FLAG_BUNDLE_MASK alone. I would love to see Jakub's
> bitfield stuff be used more. Kalle, thoughts?
Yeah, the bitfield macros are handy and we should definitely switch to
them (slowly). But definitely not a must for these SDIO patches, more
like a nice bonus.
--=20
Kalle Valo=
^ permalink raw reply
* Re: [RFC 10/12] ath10k: Added QCA65XX hw definition
From: Michal Kazior @ 2016-11-15 10:34 UTC (permalink / raw)
To: Erik Stromdahl; +Cc: Kalle Valo, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <1479141222-8493-11-git-send-email-erik.stromdahl@gmail.com>
On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> wro=
te:
> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
> ---
> drivers/net/wireless/ath/ath10k/hw.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/=
ath/ath10k/hw.h
> index 46142e9..ef45ecf 100644
> --- a/drivers/net/wireless/ath/ath10k/hw.h
> +++ b/drivers/net/wireless/ath/ath10k/hw.h
> @@ -224,6 +224,7 @@ enum ath10k_hw_rev {
> ATH10K_HW_QCA9377,
> ATH10K_HW_QCA4019,
> ATH10K_HW_QCA9887,
> + ATH10K_HW_QCA65XX,
Are you 100% positive that you're supporting all QCA65XX chips? The
rule of thumb is to avoid Xs as much as possible unless totally
perfectly completely sure.
Micha=C5=82
^ permalink raw reply
* Re: [RFC 09/12] ath10k: Mailbox address definitions
From: Michal Kazior @ 2016-11-15 10:31 UTC (permalink / raw)
To: Erik Stromdahl; +Cc: Kalle Valo, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <1479141222-8493-10-git-send-email-erik.stromdahl@gmail.com>
On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> wro=
te:
> Address definitions for SDIO/mbox based chipsets.
>
> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
> ---
> drivers/net/wireless/ath/ath10k/hw.h | 53 ++++++++++++++++++++++++++++=
++++++
> 1 file changed, 53 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/=
ath/ath10k/hw.h
> index 883547f..46142e9 100644
> --- a/drivers/net/wireless/ath/ath10k/hw.h
> +++ b/drivers/net/wireless/ath/ath10k/hw.h
> @@ -814,6 +814,59 @@ struct ath10k_hw_ops {
> #define QCA9887_EEPROM_ADDR_LO_MASK 0x00ff0000
> #define QCA9887_EEPROM_ADDR_LO_LSB 16
>
> +#define MBOX_RESET_CONTROL_ADDRESS 0x00000000
> +#define MBOX_HOST_INT_STATUS_ADDRESS 0x00000800
> +#define MBOX_HOST_INT_STATUS_ERROR_LSB 7
> +#define MBOX_HOST_INT_STATUS_ERROR_MASK 0x00000080
I would again suggest using Jakub's bitfield GET_FIELD stuff to get
rid of MASK+LSB and just have single define per register field. Kalle,
thoughts?
Micha=C5=82
^ permalink raw reply
* Re: [RFC 06/12] ath10k: bmi: Added SOC reg read/write functions
From: Michal Kazior @ 2016-11-15 10:28 UTC (permalink / raw)
To: Erik Stromdahl; +Cc: Kalle Valo, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <1479141222-8493-7-git-send-email-erik.stromdahl@gmail.com>
On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> wro=
te:
> Added functions implementing the following BMI commands:
>
> BMI_READ_SOC_REGISTER
> BMI_WRITE_SOC_REGISTER
>
> Reading and writing BMI registers is sometimes needed for
> SDIO chipsets.
I didn't see ath10k_bmi_write_soc_reg nor ath10k_bmi_read_soc_reg
being used in your Patch 12. Is this patch really necessary?
[...]
> diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless=
/ath/ath10k/bmi.c
> index 2872d34..1c378a2 100644
> --- a/drivers/net/wireless/ath/ath10k/bmi.c
> +++ b/drivers/net/wireless/ath/ath10k/bmi.c
> @@ -97,7 +97,8 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
> u32 rxlen;
> int ret;
>
> - ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n=
",
> + ath10k_dbg(ar, ATH10K_DBG_BMI,
> + "bmi read memory address 0x%x length %d\n",
> address, length);
>
> if (ar->bmi.done_sent) {
> @@ -137,7 +138,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
> u32 txlen;
> int ret;
>
> - ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\=
n",
> + ath10k_dbg(ar, ATH10K_DBG_BMI,
> + "bmi write memory address 0x%x length %d\n",
> address, length);
>
These 2 hunks shouldn't be modified in this patch. If you want to do a
clean up this warrants a separate patch :)
Micha=C5=82
^ permalink raw reply
* Re: [RFC 05/12] ath10k: htc: Added ATH10K_HTC_FLAG_BUNDLE_LSB
From: Michal Kazior @ 2016-11-15 10:25 UTC (permalink / raw)
To: Erik Stromdahl; +Cc: Kalle Valo, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <1479141222-8493-6-git-send-email-erik.stromdahl@gmail.com>
On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> wro=
te:
> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
> ---
> drivers/net/wireless/ath/ath10k/htc.h | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless=
/ath/ath10k/htc.h
> index 589800a..df16a04 100644
> --- a/drivers/net/wireless/ath/ath10k/htc.h
> +++ b/drivers/net/wireless/ath/ath10k/htc.h
> @@ -62,6 +62,8 @@ enum ath10k_htc_rx_flags {
> ATH10K_HTC_FLAG_BUNDLE_MASK =3D 0xF0
> };
>
> +#define ATH10K_HTC_FLAG_BUNDLE_LSB 4
Just an idea - we could start using FIELD_GET() with
ATH10K_HTC_FLAG_BUNDLE_MASK alone. I would love to see Jakub's
bitfield stuff be used more. Kalle, thoughts?
Micha=C5=82
^ permalink raw reply
* Re: [RFC 04/12] ath10k: htc: refactorization
From: Michal Kazior @ 2016-11-15 10:19 UTC (permalink / raw)
To: Erik Stromdahl; +Cc: Kalle Valo, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <1479141222-8493-5-git-send-email-erik.stromdahl@gmail.com>
On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> wro=
te:
> Code refactorization:
>
> Moved the code for ep 0 in ath10k_htc_rx_completion_handler
> to ath10k_htc_control_rx_complete.
>
> This eases the implementation of SDIO/mbox significantly since
> the ep_rx_complete cb is invoked directly from the SDIO/mbox
> hif layer.
>
> Since the ath10k_htc_control_rx_complete already is present
> (only containing a warning message) there is no reason for not
> using it (instead of having a special case for ep 0 in
> ath10k_htc_rx_completion_handler).
This should be squashed with Patch 3 since it's inseparable part of
the same refactorization.
Micha=C5=82
^ permalink raw reply
* Re: [RFC 03/12] ath10k: htc: Changed order of wait target and ep connect
From: Michal Kazior @ 2016-11-15 10:13 UTC (permalink / raw)
To: Erik Stromdahl; +Cc: Kalle Valo, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <1479141222-8493-4-git-send-email-erik.stromdahl@gmail.com>
On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> wro=
te:
> This patch changes the order in which the driver waits for the
> target to become ready and the service connect of the HTC
> control service.
>
> The HTC control service is connected before the driver starts
> waiting for the HTC ready control message.
>
> The reason for this is that the HTC ready control message is
> transmitted on EP 0 and that sdio/mbox based systems will ignore
> messages received on unconnected endpoints.
>
> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
> ---
> drivers/net/wireless/ath/ath10k/htc.c | 32 ++++++++++++++++-----------=
-----
> 1 file changed, 16 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless=
/ath/ath10k/htc.c
> index e3f7bf4..7257366 100644
> --- a/drivers/net/wireless/ath/ath10k/htc.c
> +++ b/drivers/net/wireless/ath/ath10k/htc.c
> @@ -606,6 +606,22 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
> u16 credit_count;
> u16 credit_size;
>
> + /* setup our pseudo HTC control endpoint connection */
> + memset(&conn_req, 0, sizeof(conn_req));
> + memset(&conn_resp, 0, sizeof(conn_resp));
> + conn_req.ep_ops.ep_tx_complete =3D ath10k_htc_control_tx_complete=
;
> + conn_req.ep_ops.ep_rx_complete =3D ath10k_htc_control_rx_complete=
;
> + conn_req.max_send_queue_depth =3D ATH10K_NUM_CONTROL_TX_BUFFERS;
> + conn_req.service_id =3D ATH10K_HTC_SVC_ID_RSVD_CTRL;
> +
> + /* connect fake service */
> + status =3D ath10k_htc_connect_service(htc, &conn_req, &conn_resp)=
;
> + if (status) {
> + ath10k_err(ar, "could not connect to htc service (%d)\n",
> + status);
> + return status;
> + }
> +
How is this supposed to work? ath10k_htc_connect_service() requires
htc->target_credit_size to compute tx_credits_per_max_message. Or am I
missing something? Applying this patch alone results in:
[ 6.680101] divide error: 0000 [#1] SMP
[ 6.681342] Modules linked in: ath10k_pci(O) ath10k_core(O) ath
mac80211 cfg80211
[ 6.684876] CPU: 3 PID: 823 Comm: kworker/u8:2 Tainted: G W
O 4.9.0-rc4-wt-ath+ #79
[ 6.688051] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS 1.7.5-20140531_083030-gandalf 04/01/2014
[ 6.691644] Workqueue: ath10k_wq ath10k_core_register_work [ath10k_core]
[ 6.694309] task: ffff88000a190000 task.stack: ffffc900006d4000
[ 6.695458] RIP: 0010:[<ffffffffa01ae46b>] [<ffffffffa01ae46b>]
ath10k_htc_connect_service+0x21b/0x420 [ath10k_core]
Micha=C5=82
^ permalink raw reply
* [PATCH 4.9.0-rc5] AR9300 calibration problems with antenna selected
From: Krzysztof Hałasa @ 2016-11-15 9:56 UTC (permalink / raw)
To: QCA ath9k Development, Kalle Valo, linux-wireless, ath9k-devel,
netdev, linux-kernel
Hi,
I recently tried to select a single antenna on AR9300 and it works for
30 seconds only. The subsequent calibration makes the RX signal level to
drop from the usual -30/-40 dBm to -70/-80 dBm, and the transmission
practically stops.
With the attached patch it works, though selecting the antenna doesn't
seem to have any visible effect, at least with "iw wlanX station dump"
(perhaps it works for TX).
I'm using ad-hoc mode:
rmmod ath9k
modprobe ath9k
iw dev wlan0 set type ibss
iw phy phyX set antenna 2
ip link set up dev wlan0
iw dev wlan0 set bitrates legacy-2.4 18
iw dev wlan0 ibss join nameXXX freqYYY
ip addr add ZZZ broadcast + dev wlan0
The card in question is Mikrotik (Routerboard) R11e-2HPnD mPCIe adapter:
AR9580 Wireless Network Adapter (rev 01), ID 168c:0033, subsystem
19b6:d016.
ieee80211 phy0: Atheros AR9300 Rev:4 mem=0xc0f40000, irq=334
https://routerboard.com/R11e-2HPnD
Linux 4.9.0-rc5.
Is there a better way?
Signed-off-by: Krzysztof Halasa <khalasa@piap.pl>
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index e9f32b5..7f17e5d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2245,7 +2245,7 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
return 0;
/* AR9100 runs into calibration issues if not all rx chains are enabled */
- if (AR_SREV_9100(ah))
+ if (AR_SREV_9100(ah) || AR_SREV_9300(ah))
ah->rxchainmask = 0x7;
else
ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
--
Krzysztof Halasa
Industrial Research Institute for Automation and Measurements PIAP
Al. Jerozolimskie 202, 02-486 Warsaw, Poland
^ permalink raw reply related
* Re: [RFC 02/12] ath10k: htc: rx trailer lookahead support
From: Michal Kazior @ 2016-11-15 9:57 UTC (permalink / raw)
To: Erik Stromdahl; +Cc: Kalle Valo, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <1479141222-8493-3-git-send-email-erik.stromdahl@gmail.com>
On 14 November 2016 at 17:33, Erik Stromdahl <erik.stromdahl@gmail.com> wro=
te:
> The RX trailer parsing is now capable of parsing lookahead reports.
> This is needed by SDIO/mbox.
It'd be useful to know what exactly lookahead will be used for. What
payload does it carry.
> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
> ---
> drivers/net/wireless/ath/ath10k/htc.c | 91 +++++++++++++++++++++++++++=
+++++-
> drivers/net/wireless/ath/ath10k/htc.h | 30 +++++++++--
> 2 files changed, 116 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless=
/ath/ath10k/htc.c
> index 26b1e15..e3f7bf4 100644
> --- a/drivers/net/wireless/ath/ath10k/htc.c
> +++ b/drivers/net/wireless/ath/ath10k/htc.c
> @@ -228,10 +228,74 @@ void ath10k_htc_tx_completion_handler(struct ath10k=
*ar, struct sk_buff *skb)
> spin_unlock_bh(&htc->tx_lock);
> }
>
> +static int
> +ath10k_htc_process_lookahead(struct ath10k_htc *htc,
> + const struct ath10k_htc_lookahead_report *re=
port,
> + int len,
> + enum ath10k_htc_ep_id eid,
> + u32 *next_lk_ahds,
next_lk_ahds should be u8 or void. From what I understand by glancing
through the code it is an agnostic buffer that carries payload which
is later interpreted either as eid or htc header, right? void is
probably most suitable in this case for passing around and u8 for
inline-based storage.
I'd also avoid silly abbreviations. Probably "lookahead" alone is enough.
> + int *next_lk_ahds_len)
> +{
> + struct ath10k *ar =3D htc->ar;
> +
> + if (report->pre_valid !=3D ((~report->post_valid) & 0xFF))
> + /* Invalid lookahead flags are actually transmitted by
> + * the target in the HTC control message.
> + * Since this will happen at every boot we silently ignor=
e
> + * the lookahead in this case
> + */
I'd put this comment before the if().
> + return 0;
> +
> + if (next_lk_ahds && next_lk_ahds_len) {
> + ath10k_dbg(ar, ATH10K_DBG_HTC,
> + "htc rx lk_ahd found pre_valid 0x%x post_valid=
0x%x\n",
> + report->pre_valid, report->post_valid);
> +
> + /* look ahead bytes are valid, copy them over */
> + memcpy((u8 *)&next_lk_ahds[0], report->lk_ahd, 4);
> +
> + *next_lk_ahds_len =3D 1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +ath10k_htc_process_lookahead_bundle(struct ath10k_htc *htc,
> + const struct ath10k_htc_lookahead_rep=
ort_bundle *report,
> + int len,
> + enum ath10k_htc_ep_id eid,
> + u32 *next_lk_ahds,
Ditto. void.
> + int *next_lk_ahds_len)
> +{
> + int bundle_cnt =3D len / sizeof(*report);
> +
> + if (!bundle_cnt || (bundle_cnt > HTC_HOST_MAX_MSG_PER_BUNDLE)) {
> + WARN_ON(1);
This should be ath10k_warn() instead. This isn't internal driver flow
assertion. It is possible firmware bug or revision misalignment
instead.
> + return -EINVAL;
> + }
> +
> + if (next_lk_ahds && next_lk_ahds_len) {
> + int i;
> +
> + for (i =3D 0; i < bundle_cnt; i++) {
> + memcpy((u8 *)&next_lk_ahds[i], report->lk_ahd,
> + sizeof(u32));
You'll need to re-adjust the &x[i] to maintain proper offset with void poin=
ter.
Micha=C5=82
^ permalink raw reply
* Re: Bayesian rate control
From: Johannes Berg @ 2016-11-15 9:34 UTC (permalink / raw)
To: Adrian Chadd
Cc: Björn Smedman, linux-wireless@vger.kernel.org, ath9k-devel
In-Reply-To: <CAJ-Vmo=OM=rx-RM0fg=0dY9Jy_9njsFCnuXEPEngrFDj40-mBg@mail.gmail.com>
> But there is a per-descriptor TX rate table entry in the driver.
> FreeBSD uses it to implement its rate control for the intel drivers.
>
> What am I missing? :)
Not sure. But there isn't a per-descriptor table in the driver. There's
a per-station table, that *can* be used in similar ways, but at least
in Linux none of the APIs are hooked up to the general implementation,
it's all driver/device-specific code, so it'd be very painful to try to
experiment with.
johannes
^ permalink raw reply
* Re: [PATCH 1/2] cfg80211: Add support to set tx power for a station associated
From: Johannes Berg @ 2016-11-15 9:31 UTC (permalink / raw)
To: Ashok Raj Nagarajan, Ben Greear
Cc: Ashok Raj Nagarajan, linux-wireless, ath10k
In-Reply-To: <8908f6e7bb8ca043fbeb07ee8b004e8f@codeaurora.org>
> In the case of manual intervention by user, the firmware will check
> three
> values - regulatory domain, automatic tx power and user entered
> value.
> System
> will always cap to the minimum of these values and see to that we do
> not
> exceed
> the regulatory power limits.
Fair enough.
> If there are no more comments I will resent this patch series after
> rebase.
I suspect we should also have some kind of capability for all of this,
so it can be used reliably?
johannes
^ permalink raw reply
* Re: [PATCH V3] qtnfmac: announcement of new FullMAC driver for Quantenna chipsets
From: Johannes Berg @ 2016-11-15 9:06 UTC (permalink / raw)
To: igor.mitsyanko.os, linux-wireless
Cc: btherthala, hwang, smaksimenko, dlebed, Sergey Matyukevich,
Kamlesh Rath, Avinash Patil
In-Reply-To: <1478700000-11624-2-git-send-email-igor.mitsyanko.os@quantenna.com>
On Wed, 2016-11-09 at 17:00 +0300, igor.mitsyanko.os@quantenna.com
wrote:
> +static int
> +qtnf_change_virtual_intf(struct wiphy *wiphy,
> + struct net_device *dev,
> + enum nl80211_iftype type, u32 *flags,
> + struct vif_params *params)
> +{
> + struct qtnf_vif *vif;
> + u8 *mac_addr;
> +
> + vif = qtnf_netdev_get_priv(dev);
> +
> + if (params)
> + mac_addr = params->macaddr;
> + else
> + mac_addr = NULL;
> +
> + if (qtnf_cmd_send_change_intf_type(vif, type, mac_addr)) {
> + pr_err("failed to change interface type\n");
> + return -EFAULT;
> + }
> +
> + vif->wdev.iftype = type;
> + return 0;
> +}
Do you really support arbitrary type changes?
You might even have to handle ongoing scans, etc.
> + /* Clear the vif in mac */
"mac"? Maybe you mean cfg80211?
> + vif->netdev->ieee80211_ptr = NULL;
> + vif->netdev = NULL;
> + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
> + eth_zero_addr(vif->mac_addr);
> +
> + return 0;
> +}
But I'm not sure this makes sense? You're not actually deleting the
interface here, so why sever all the links/clear all the data?
> +/* concatenate all the beacon IEs into one buffer
> + * Take IEs from head, tail and beacon_ies fields of
cfg80211_beacon_data
> + * and append it to provided buffer.
> + * Checks total IE buf length to be <= than IEEE80211_MAX_DATA_LEN.
> + * Checks IE buffers to be valid, so that resulting buffer
> + * should be a valid IE buffer with length <=
IEEE80211_MAX_DATA_LEN.
> + */
I'm not sure this is right - beacon_ies is head+tail already, I think?
> +static int
> +qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev,
> + int idx, u8 *mac, struct station_info *sinfo)
> +{
> + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
> + const struct qtnf_sta_node *sta_node;
> + int ret;
> +
> + sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx);
> +
> + if (unlikely(!sta_node))
> + return -ENOENT;
> +
> + ether_addr_copy(mac, sta_node->mac_addr);
> +
> + ret = qtnf_cmd_get_sta_info(vif, sta_node->mac_addr, sinfo);
> +
> + if (unlikely(ret == -ENOENT)) {
> + sinfo->filled = 0;
> + ret = 0;
> + }
This case seems slightly odd - what does it mean that the station
existed, but getting the information returned -ENOENT? Is that because
it's racy, somehow? If so, wouldn't it be better to take this as an
indication that the station doesn't exist, and skip this entry entirely
or something?
> + /* nofity cfg80211 */
typo :)
> + while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
> + tlv_type = le16_to_cpu(tlv->type);
> + tlv_value_len = le16_to_cpu(tlv->len);
> + tlv_full_len = tlv_value_len + sizeof(struct
qlink_tlv_hdr);
> +
> + if (tlv_full_len > payload_len) {
> + pr_warn("malformed TLV 0x%.2X; LEN: %u\n",
> + tlv_type, tlv_value_len);
> + return -EINVAL;
> + }
> +
> + if (tlv_type == QTN_TLV_ID_IE_SET) {
> + ies = tlv->val;
> + ies_len = tlv_value_len;
> + }
> +
> + payload_len -= tlv_full_len;
> + tlv = (struct qlink_tlv_hdr *)(tlv->val +
tlv_value_len);
> + }
> +
> + if (payload_len) {
> + pr_warn("malformed IEs buf; bytes left: %zu\n",
payload_len);
> + return -EINVAL;
> + }
Don't you mean "malformed TLVs buf"? It's obviously similar, but you
refer to this encoding as TLV, not IE.
Maybe you should ignore it too, since it's a firmware bug?
> + qdev_vif = netdev_priv(dev);
> + *((unsigned long *)qdev_vif) = (unsigned long)vif;
This seems very strange - why unsigned long, rather than void? I mean
*(void **)qdev_vif = vif;
> +static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv)
> +{
> + struct qtnf_shm_ipc_region __iomem *ipc_tx_reg;
> + struct qtnf_shm_ipc_region __iomem *ipc_rx_reg;
> + const struct qtnf_shm_ipc_int ipc_int = {
qtnf_ipc_gen_ep_int, priv };
> + const struct qtnf_shm_ipc_rx_callback rx_callback = {
> + qtnf_pcie_control_rx_callbac
k, priv };
If those are const, why not also static? In fact, it seems they really
should be, since they're registered below?
> +static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv)
> +{
> + unsigned long vaddr;
> + dma_addr_t paddr;
> + int len;
> +
> + len = priv->tx_bd_num * sizeof(struct qtnf_tx_bd) +
> + priv->rx_bd_num * sizeof(struct qtnf_rx_bd);
> +
> + vaddr = (unsigned long)dmam_alloc_coherent(&priv->pdev->dev,
> + len, &paddr,
GFP_KERNEL);
> + if (!vaddr)
> + return -ENOMEM;
> +
> + /* tx bd */
> +
> + memset((void *)vaddr, 0, len);
Those unsigned long/void * casts look strange too. Why not use a "void
*vaddr" to start with?
> + priv->bd_table_vaddr = vaddr;
Maybe need a cast here, if that variable is needed at all (identical to
tx_bd_vbase), or make that struct member also void *?
> + priv->bd_table_paddr = paddr;
> + priv->bd_table_len = len;
> +
> + priv->tx_bd_vbase = (struct qtnf_tx_bd *)vaddr;
Don't even need that cast then.
> + priv->tx_bd_pbase = paddr;
> +
> + pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n",
> + (void *)vaddr, &paddr);
> +
> + priv->tx_bd_reclaim_start = 0;
> + priv->tx_bd_index = 0;
> + priv->tx_queue_len = 0;
> +
> + /* rx bd */
> +
> + vaddr += priv->tx_bd_num * sizeof(struct qtnf_tx_bd);
Here you can do something like
vaddr = ((struct qtnf_tx_bd)vaddr) + priv->tx_bd_num;
> + paddr += priv->tx_bd_num * sizeof(struct qtnf_tx_bd);
> +
> + priv->rx_bd_vbase = (struct qtnf_rx_bd *)vaddr;
no need for the cast here then.
> + priv->rx_bd_pbase = paddr;
> +
> + writel(QTN_HOST_LO32(paddr),
> + PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base));
> + writel(QTN_HOST_HI32(paddr),
> + PCIE_HDP_TX_HOST_Q_BASE_H(priv->pcie_reg_base));
> + writel(priv->rx_bd_num | (sizeof(struct qtnf_rx_bd)) << 16,
> + PCIE_HDP_TX_HOST_Q_SZ_CTRL(priv->pcie_reg_base));
> +
> + priv->hw_txproc_wr_ptr = priv->rx_bd_num -
rx_bd_reserved_param;
> +
> + writel(priv->hw_txproc_wr_ptr,
> + PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base));
> +
> + pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n",
> + (void *)vaddr, &paddr);
Nor here.
On the whole, it probably doesn't really matter (I'd let Kalle decide I
guess). Just looks odd to me.
> + /* sync up all descriptor updates before passing them to EP
*/
> + wmb();
I think you need dma_wmb()?
So I mostly looked at the cfg80211 bits, obviously - the other comments
were just in passing.
I also didn't review the flows - some of these things are tricky (e.g.
are there races between userspace asking to disconnect, and disconnect
notification, and similar). Maybe it helps anyway :)
johannes
^ permalink raw reply
* [PATCH v5 1/5] soc: qcom: smem_state: Fix include for ERR_PTR()
From: Bjorn Andersson @ 2016-11-15 6:06 UTC (permalink / raw)
To: Eugene Krasnikov, Kalle Valo
Cc: Andy Gross, wcn36xx, linux-wireless, netdev, linux-kernel,
linux-arm-msm
The correct include file for getting errno constants and ERR_PTR() is
linux/err.h, rather than linux/errno.h, so fix the include.
Fixes: e8b123e60084 ("soc: qcom: smem_state: Add stubs for disabled smem_state")
Acked-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Kalle, please merge this patch through your tree.
Changes since v4:
- New patch
include/linux/soc/qcom/smem_state.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/soc/qcom/smem_state.h b/include/linux/soc/qcom/smem_state.h
index 7b88697929e9..b8478ee7a71f 100644
--- a/include/linux/soc/qcom/smem_state.h
+++ b/include/linux/soc/qcom/smem_state.h
@@ -1,7 +1,7 @@
#ifndef __QCOM_SMEM_STATE__
#define __QCOM_SMEM_STATE__
-#include <linux/errno.h>
+#include <linux/err.h>
struct device_node;
struct qcom_smem_state;
--
2.5.0
^ permalink raw reply related
* [PATCH v5 2/5] wcn36xx: Transition driver to SMD client
From: Bjorn Andersson @ 2016-11-15 6:06 UTC (permalink / raw)
To: Eugene Krasnikov, Kalle Valo
Cc: wcn36xx, linux-wireless, netdev, linux-kernel, linux-arm-msm,
Andy Gross
In-Reply-To: <1479190014-11297-1-git-send-email-bjorn.andersson@linaro.org>
The wcn36xx wifi driver follows the life cycle of the WLAN_CTRL SMD
channel, as such it should be a SMD client. This patch makes this
transition, now that we have the necessary frameworks available.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Changes since v4:
- Added Kconfig dependency to handle dependencies compiled as modules
drivers/net/wireless/ath/wcn36xx/Kconfig | 2 +
drivers/net/wireless/ath/wcn36xx/dxe.c | 16 +++---
drivers/net/wireless/ath/wcn36xx/main.c | 79 ++++++++++++++++++++----------
drivers/net/wireless/ath/wcn36xx/smd.c | 31 +++++-------
drivers/net/wireless/ath/wcn36xx/smd.h | 5 ++
drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 21 +++-----
6 files changed, 88 insertions(+), 66 deletions(-)
diff --git a/drivers/net/wireless/ath/wcn36xx/Kconfig b/drivers/net/wireless/ath/wcn36xx/Kconfig
index 591ebaea8265..4b83e87f0b94 100644
--- a/drivers/net/wireless/ath/wcn36xx/Kconfig
+++ b/drivers/net/wireless/ath/wcn36xx/Kconfig
@@ -1,6 +1,8 @@
config WCN36XX
tristate "Qualcomm Atheros WCN3660/3680 support"
depends on MAC80211 && HAS_DMA
+ depends on QCOM_WCNSS_CTRL || QCOM_WCNSS_CTRL=n
+ depends on QCOM_SMD || QCOM_SMD=n
---help---
This module adds support for wireless adapters based on
Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 231fd022f0f5..87dfdaf9044c 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -23,6 +23,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/interrupt.h>
+#include <linux/soc/qcom/smem_state.h>
#include "wcn36xx.h"
#include "txrx.h"
@@ -151,9 +152,12 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
goto out_err;
/* Initialize SMSM state Clear TX Enable RING EMPTY STATE */
- ret = wcn->ctrl_ops->smsm_change_state(
- WCN36XX_SMSM_WLAN_TX_ENABLE,
- WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+ ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
+ WCN36XX_SMSM_WLAN_TX_ENABLE |
+ WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
+ WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+ if (ret)
+ goto out_err;
return 0;
@@ -678,9 +682,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
* notify chip about new frame through SMSM bus.
*/
if (is_low && vif_priv->pw_state == WCN36XX_BMPS) {
- wcn->ctrl_ops->smsm_change_state(
- 0,
- WCN36XX_SMSM_WLAN_TX_ENABLE);
+ qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
+ WCN36XX_SMSM_WLAN_TX_ENABLE,
+ WCN36XX_SMSM_WLAN_TX_ENABLE);
} else {
/* indicate End Of Packet and generate interrupt on descriptor
* done.
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index e1d59da2ad20..3c2522b07c90 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -21,6 +21,10 @@
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/smem_state.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
#include "wcn36xx.h"
unsigned int wcn36xx_dbg_mask;
@@ -1058,8 +1062,7 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
int ret;
/* Set TX IRQ */
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- "wcnss_wlantx_irq");
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx");
if (!res) {
wcn36xx_err("failed to get tx_irq\n");
return -ENOENT;
@@ -1067,14 +1070,29 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
wcn->tx_irq = res->start;
/* Set RX IRQ */
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- "wcnss_wlanrx_irq");
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "rx");
if (!res) {
wcn36xx_err("failed to get rx_irq\n");
return -ENOENT;
}
wcn->rx_irq = res->start;
+ /* Acquire SMSM tx enable handle */
+ wcn->tx_enable_state = qcom_smem_state_get(&pdev->dev,
+ "tx-enable", &wcn->tx_enable_state_bit);
+ if (IS_ERR(wcn->tx_enable_state)) {
+ wcn36xx_err("failed to get tx-enable state\n");
+ return PTR_ERR(wcn->tx_enable_state);
+ }
+
+ /* Acquire SMSM tx rings empty handle */
+ wcn->tx_rings_empty_state = qcom_smem_state_get(&pdev->dev,
+ "tx-rings-empty", &wcn->tx_rings_empty_state_bit);
+ if (IS_ERR(wcn->tx_rings_empty_state)) {
+ wcn36xx_err("failed to get tx-rings-empty state\n");
+ return PTR_ERR(wcn->tx_rings_empty_state);
+ }
+
mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
if (!mmio_node) {
wcn36xx_err("failed to acquire qcom,mmio reference\n");
@@ -1115,11 +1133,14 @@ static int wcn36xx_probe(struct platform_device *pdev)
{
struct ieee80211_hw *hw;
struct wcn36xx *wcn;
+ void *wcnss;
int ret;
- u8 addr[ETH_ALEN];
+ const u8 *addr;
wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
+ wcnss = dev_get_drvdata(pdev->dev.parent);
+
hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
if (!hw) {
wcn36xx_err("failed to alloc hw\n");
@@ -1130,11 +1151,23 @@ static int wcn36xx_probe(struct platform_device *pdev)
wcn = hw->priv;
wcn->hw = hw;
wcn->dev = &pdev->dev;
- wcn->ctrl_ops = pdev->dev.platform_data;
-
mutex_init(&wcn->hal_mutex);
- if (!wcn->ctrl_ops->get_hw_mac(addr)) {
+ wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process);
+ if (IS_ERR(wcn->smd_channel)) {
+ wcn36xx_err("failed to open WLAN_CTRL channel\n");
+ ret = PTR_ERR(wcn->smd_channel);
+ goto out_wq;
+ }
+
+ qcom_smd_set_drvdata(wcn->smd_channel, hw);
+
+ addr = of_get_property(pdev->dev.of_node, "local-mac-address", &ret);
+ if (addr && ret != ETH_ALEN) {
+ wcn36xx_err("invalid local-mac-address\n");
+ ret = -EINVAL;
+ goto out_wq;
+ } else if (addr) {
wcn36xx_info("mac address: %pM\n", addr);
SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
}
@@ -1158,6 +1191,7 @@ static int wcn36xx_probe(struct platform_device *pdev)
out_err:
return ret;
}
+
static int wcn36xx_remove(struct platform_device *pdev)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
@@ -1168,42 +1202,33 @@ static int wcn36xx_remove(struct platform_device *pdev)
mutex_destroy(&wcn->hal_mutex);
ieee80211_unregister_hw(hw);
+
+ qcom_smem_state_put(wcn->tx_enable_state);
+ qcom_smem_state_put(wcn->tx_rings_empty_state);
+
iounmap(wcn->dxe_base);
iounmap(wcn->ccu_base);
ieee80211_free_hw(hw);
return 0;
}
-static const struct platform_device_id wcn36xx_platform_id_table[] = {
- {
- .name = "wcn36xx",
- .driver_data = 0
- },
+
+static const struct of_device_id wcn36xx_of_match[] = {
+ { .compatible = "qcom,wcnss-wlan" },
{}
};
-MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
+MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
static struct platform_driver wcn36xx_driver = {
.probe = wcn36xx_probe,
.remove = wcn36xx_remove,
.driver = {
.name = "wcn36xx",
+ .of_match_table = wcn36xx_of_match,
},
- .id_table = wcn36xx_platform_id_table,
};
-static int __init wcn36xx_init(void)
-{
- platform_driver_register(&wcn36xx_driver);
- return 0;
-}
-module_init(wcn36xx_init);
-
-static void __exit wcn36xx_exit(void)
-{
- platform_driver_unregister(&wcn36xx_driver);
-}
-module_exit(wcn36xx_exit);
+module_platform_driver(wcn36xx_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index a443992320f2..af0260add841 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -19,6 +19,7 @@
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <linux/bitops.h>
+#include <linux/soc/qcom/smd.h>
#include "smd.h"
struct wcn36xx_cfg_val {
@@ -253,7 +254,7 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
init_completion(&wcn->hal_rsp_compl);
start = jiffies;
- ret = wcn->ctrl_ops->tx(wcn->hal_buf, len);
+ ret = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
if (ret) {
wcn36xx_err("HAL TX failed\n");
goto out;
@@ -2180,9 +2181,12 @@ int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
return ret;
}
-static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
+int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
+ const void *buf, size_t len)
{
- struct wcn36xx_hal_msg_header *msg_header = buf;
+ const struct wcn36xx_hal_msg_header *msg_header = buf;
+ struct ieee80211_hw *hw = qcom_smd_get_drvdata(channel);
+ struct wcn36xx *wcn = hw->priv;
struct wcn36xx_hal_ind_msg *msg_ind;
wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
@@ -2233,15 +2237,11 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
- msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_KERNEL);
+ msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
if (!msg_ind) {
- /*
- * FIXME: Do something smarter then just
- * printing an error.
- */
wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
msg_header->msg_type);
- break;
+ return -ENOMEM;
}
msg_ind->msg_len = len;
@@ -2257,6 +2257,8 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
wcn36xx_err("SMD_EVENT (%d) not supported\n",
msg_header->msg_type);
}
+
+ return 0;
}
static void wcn36xx_ind_smd_work(struct work_struct *work)
{
@@ -2315,22 +2317,13 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
INIT_LIST_HEAD(&wcn->hal_ind_queue);
spin_lock_init(&wcn->hal_ind_lock);
- ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
- if (ret) {
- wcn36xx_err("failed to open control channel\n");
- goto free_wq;
- }
-
- return ret;
+ return 0;
-free_wq:
- destroy_workqueue(wcn->hal_ind_wq);
out:
return ret;
}
void wcn36xx_smd_close(struct wcn36xx *wcn)
{
- wcn->ctrl_ops->close();
destroy_workqueue(wcn->hal_ind_wq);
}
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index df80cbbd9d1b..40d829563c2b 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -51,6 +51,7 @@ struct wcn36xx_hal_ind_msg {
};
struct wcn36xx;
+struct qcom_smd_channel;
int wcn36xx_smd_open(struct wcn36xx *wcn);
void wcn36xx_smd_close(struct wcn36xx *wcn);
@@ -127,6 +128,10 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
+
+int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
+ const void *buf, size_t len);
+
int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
struct ieee80211_vif *vif,
struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 22242d18e1fe..68cc06cf9bc0 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -103,19 +103,6 @@ struct nv_data {
u8 table;
};
-/* Interface for platform control path
- *
- * @open: hook must be called when wcn36xx wants to open control channel.
- * @tx: sends a buffer.
- */
-struct wcn36xx_platform_ctrl_ops {
- int (*open)(void *drv_priv, void *rsp_cb);
- void (*close)(void);
- int (*tx)(char *buf, size_t len);
- int (*get_hw_mac)(u8 *addr);
- int (*smsm_change_state)(u32 clear_mask, u32 set_mask);
-};
-
/**
* struct wcn36xx_vif - holds VIF related fields
*
@@ -205,7 +192,13 @@ struct wcn36xx {
void __iomem *ccu_base;
void __iomem *dxe_base;
- struct wcn36xx_platform_ctrl_ops *ctrl_ops;
+ struct qcom_smd_channel *smd_channel;
+
+ struct qcom_smem_state *tx_enable_state;
+ unsigned tx_enable_state_bit;
+ struct qcom_smem_state *tx_rings_empty_state;
+ unsigned tx_rings_empty_state_bit;
+
/*
* smd_buf must be protected with smd_mutex to garantee
* that all messages are sent one after another
--
2.5.0
^ permalink raw reply related
* [PATCH v5 4/5] wcn36xx: Implement print_reg indication
From: Bjorn Andersson @ 2016-11-15 6:06 UTC (permalink / raw)
To: Eugene Krasnikov, Kalle Valo
Cc: wcn36xx, linux-wireless, netdev, linux-kernel, linux-arm-msm,
Andy Gross, Nicolas Dechesne
In-Reply-To: <1479190014-11297-1-git-send-email-bjorn.andersson@linaro.org>
Some firmware versions sends a "print register indication", handle this
by printing out the content.
Cc: Nicolas Dechesne <ndec@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Changes since v4:
- None
drivers/net/wireless/ath/wcn36xx/hal.h | 16 ++++++++++++++++
drivers/net/wireless/ath/wcn36xx/smd.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
index 4f87ef1e1eb8..b765c647319d 100644
--- a/drivers/net/wireless/ath/wcn36xx/hal.h
+++ b/drivers/net/wireless/ath/wcn36xx/hal.h
@@ -350,6 +350,8 @@ enum wcn36xx_hal_host_msg_type {
WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
+ WCN36XX_HAL_PRINT_REG_INFO_IND = 259,
+
WCN36XX_HAL_MSG_MAX = WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE
};
@@ -4703,4 +4705,18 @@ struct stats_class_b_ind {
u32 rx_time_total;
};
+/* WCN36XX_HAL_PRINT_REG_INFO_IND */
+struct wcn36xx_hal_print_reg_info_ind {
+ struct wcn36xx_hal_msg_header header;
+
+ u32 count;
+ u32 scenario;
+ u32 reason;
+
+ struct {
+ u32 addr;
+ u32 value;
+ } regs[];
+} __packed;
+
#endif /* _HAL_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index be5e5ea1e5c3..1c2966f7db7a 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -2109,6 +2109,30 @@ static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn,
return -ENOENT;
}
+static int wcn36xx_smd_print_reg_info_ind(struct wcn36xx *wcn,
+ void *buf,
+ size_t len)
+{
+ struct wcn36xx_hal_print_reg_info_ind *rsp = buf;
+ int i;
+
+ if (len < sizeof(*rsp)) {
+ wcn36xx_warn("Corrupted print reg info indication\n");
+ return -EIO;
+ }
+
+ wcn36xx_dbg(WCN36XX_DBG_HAL,
+ "reginfo indication, scenario: 0x%x reason: 0x%x\n",
+ rsp->scenario, rsp->reason);
+
+ for (i = 0; i < rsp->count; i++) {
+ wcn36xx_dbg(WCN36XX_DBG_HAL, "\t0x%x: 0x%x\n",
+ rsp->regs[i].addr, rsp->regs[i].value);
+ }
+
+ return 0;
+}
+
int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value)
{
struct wcn36xx_hal_update_cfg_req_msg msg_body, *body;
@@ -2237,6 +2261,7 @@ int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
case WCN36XX_HAL_OTA_TX_COMPL_IND:
case WCN36XX_HAL_MISSED_BEACON_IND:
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
+ case WCN36XX_HAL_PRINT_REG_INFO_IND:
msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
if (!msg_ind) {
wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
@@ -2296,6 +2321,11 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
hal_ind_msg->msg,
hal_ind_msg->msg_len);
break;
+ case WCN36XX_HAL_PRINT_REG_INFO_IND:
+ wcn36xx_smd_print_reg_info_ind(wcn,
+ hal_ind_msg->msg,
+ hal_ind_msg->msg_len);
+ break;
default:
wcn36xx_err("SMD_EVENT (%d) not supported\n",
msg_header->msg_type);
--
2.5.0
^ permalink raw reply related
* [PATCH v5 5/5] wcn36xx: Don't use the destroyed hal_mutex
From: Bjorn Andersson @ 2016-11-15 6:06 UTC (permalink / raw)
To: Eugene Krasnikov, Kalle Valo
Cc: wcn36xx, linux-wireless, netdev, linux-kernel, linux-arm-msm,
Andy Gross
In-Reply-To: <1479190014-11297-1-git-send-email-bjorn.andersson@linaro.org>
ieee80211_unregister_hw() might invoke operations to stop the interface,
that uses the hal_mutex. So don't destroy it until after we're done
using it.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
With this patch I can successfully (although with a SMD send timeout in the
shutdown path) start and stop the WCNSS PIL/remoteproc multiple times and the
wlan0 interface will come and go accordingly.
Will submit the necessary DT patches soon as well.
Changes since v4:
- New patch
drivers/net/wireless/ath/wcn36xx/main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 96a9584edcbb..0002190c9041 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -1241,7 +1241,6 @@ static int wcn36xx_remove(struct platform_device *pdev)
wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
release_firmware(wcn->nv);
- mutex_destroy(&wcn->hal_mutex);
ieee80211_unregister_hw(hw);
@@ -1250,6 +1249,8 @@ static int wcn36xx_remove(struct platform_device *pdev)
iounmap(wcn->dxe_base);
iounmap(wcn->ccu_base);
+
+ mutex_destroy(&wcn->hal_mutex);
ieee80211_free_hw(hw);
return 0;
--
2.5.0
^ permalink raw reply related
* [PATCH v5 3/5] wcn36xx: Implement firmware assisted scan
From: Bjorn Andersson @ 2016-11-15 6:06 UTC (permalink / raw)
To: Eugene Krasnikov, Kalle Valo
Cc: wcn36xx, linux-wireless, netdev, linux-kernel, linux-arm-msm,
Andy Gross
In-Reply-To: <1479190014-11297-1-git-send-email-bjorn.andersson@linaro.org>
Using the software based channel scan mechanism from mac80211 keeps us
offline for 10-15 second, we should instead issue a start_scan/end_scan
on each channel reducing this time.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Changes since v4:
- None
drivers/net/wireless/ath/wcn36xx/main.c | 64 +++++++++++++++++++++++++-----
drivers/net/wireless/ath/wcn36xx/smd.c | 8 ++--
drivers/net/wireless/ath/wcn36xx/smd.h | 4 +-
drivers/net/wireless/ath/wcn36xx/txrx.c | 19 ++++++---
drivers/net/wireless/ath/wcn36xx/wcn36xx.h | 9 +++++
5 files changed, 81 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 3c2522b07c90..96a9584edcbb 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -568,23 +568,59 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
-static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- const u8 *mac_addr)
+static void wcn36xx_hw_scan_worker(struct work_struct *work)
{
- struct wcn36xx *wcn = hw->priv;
+ struct wcn36xx *wcn = container_of(work, struct wcn36xx, scan_work);
+ struct cfg80211_scan_request *req = wcn->scan_req;
+ u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX];
+ struct cfg80211_scan_info scan_info = {};
+ int i;
+
+ wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 scan %d channels worker\n", req->n_channels);
+
+ for (i = 0; i < req->n_channels; i++)
+ channels[i] = req->channels[i]->hw_value;
+
+ wcn36xx_smd_update_scan_params(wcn, channels, req->n_channels);
wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
- wcn36xx_smd_start_scan(wcn);
+ for (i = 0; i < req->n_channels; i++) {
+ wcn->scan_freq = req->channels[i]->center_freq;
+ wcn->scan_band = req->channels[i]->band;
+
+ wcn36xx_smd_start_scan(wcn, req->channels[i]->hw_value);
+ msleep(30);
+ wcn36xx_smd_end_scan(wcn, req->channels[i]->hw_value);
+
+ wcn->scan_freq = 0;
+ }
+ wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+
+ scan_info.aborted = false;
+ ieee80211_scan_completed(wcn->hw, &scan_info);
+
+ mutex_lock(&wcn->scan_lock);
+ wcn->scan_req = NULL;
+ mutex_unlock(&wcn->scan_lock);
}
-static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_scan_request *hw_req)
{
struct wcn36xx *wcn = hw->priv;
- wcn36xx_smd_end_scan(wcn);
- wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+ mutex_lock(&wcn->scan_lock);
+ if (wcn->scan_req) {
+ mutex_unlock(&wcn->scan_lock);
+ return -EBUSY;
+ }
+ wcn->scan_req = &hw_req->req;
+ mutex_unlock(&wcn->scan_lock);
+
+ schedule_work(&wcn->scan_work);
+
+ return 0;
}
static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
@@ -997,8 +1033,7 @@ static const struct ieee80211_ops wcn36xx_ops = {
.configure_filter = wcn36xx_configure_filter,
.tx = wcn36xx_tx,
.set_key = wcn36xx_set_key,
- .sw_scan_start = wcn36xx_sw_scan_start,
- .sw_scan_complete = wcn36xx_sw_scan_complete,
+ .hw_scan = wcn36xx_hw_scan,
.bss_info_changed = wcn36xx_bss_info_changed,
.set_rts_threshold = wcn36xx_set_rts_threshold,
.sta_add = wcn36xx_sta_add,
@@ -1023,6 +1058,7 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS);
wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
@@ -1032,6 +1068,9 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
wcn->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wcn_band_2ghz;
wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz;
+ wcn->hw->wiphy->max_scan_ssids = WCN36XX_MAX_SCAN_SSIDS;
+ wcn->hw->wiphy->max_scan_ie_len = WCN36XX_MAX_SCAN_IE_LEN;
+
wcn->hw->wiphy->cipher_suites = cipher_suites;
wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -1152,6 +1191,9 @@ static int wcn36xx_probe(struct platform_device *pdev)
wcn->hw = hw;
wcn->dev = &pdev->dev;
mutex_init(&wcn->hal_mutex);
+ mutex_init(&wcn->scan_lock);
+
+ INIT_WORK(&wcn->scan_work, wcn36xx_hw_scan_worker);
wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process);
if (IS_ERR(wcn->smd_channel)) {
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index af0260add841..be5e5ea1e5c3 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -522,7 +522,7 @@ int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode)
return ret;
}
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel)
{
struct wcn36xx_hal_start_scan_req_msg msg_body;
int ret = 0;
@@ -530,7 +530,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ);
- msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+ msg_body.scan_channel = scan_channel;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
@@ -552,7 +552,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
return ret;
}
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel)
{
struct wcn36xx_hal_end_scan_req_msg msg_body;
int ret = 0;
@@ -560,7 +560,7 @@ int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ);
- msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+ msg_body.scan_channel = scan_channel;
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
index 40d829563c2b..8892ccd67b14 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.h
+++ b/drivers/net/wireless/ath/wcn36xx/smd.h
@@ -60,8 +60,8 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn);
int wcn36xx_smd_start(struct wcn36xx *wcn);
int wcn36xx_smd_stop(struct wcn36xx *wcn);
int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode);
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn);
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn);
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel);
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel);
int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
enum wcn36xx_hal_sys_mode mode);
int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count);
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index 1f34c2e912d7..8c387a0a3c09 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -45,9 +45,20 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
skb_put(skb, bd->pdu.mpdu_header_off + bd->pdu.mpdu_len);
skb_pull(skb, bd->pdu.mpdu_header_off);
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = __le16_to_cpu(hdr->frame_control);
+ sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
+
+ /* When scanning associate beacons to this */
+ if (ieee80211_is_beacon(hdr->frame_control) && wcn->scan_freq) {
+ status.freq = wcn->scan_freq;
+ status.band = wcn->scan_band;
+ } else {
+ status.freq = WCN36XX_CENTER_FREQ(wcn);
+ status.band = WCN36XX_BAND(wcn);
+ }
+
status.mactime = 10;
- status.freq = WCN36XX_CENTER_FREQ(wcn);
- status.band = WCN36XX_BAND(wcn);
status.signal = -get_rssi0(bd);
status.antenna = 1;
status.rate_idx = 1;
@@ -61,10 +72,6 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = __le16_to_cpu(hdr->frame_control);
- sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
-
if (ieee80211_is_beacon(hdr->frame_control)) {
wcn36xx_dbg(WCN36XX_DBG_BEACON, "beacon skb %p len %d fc %04x sn %d\n",
skb, skb->len, fc, sn);
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 68cc06cf9bc0..35a6590c3ee5 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -35,6 +35,9 @@
/* How many frames until we start a-mpdu TX session */
#define WCN36XX_AMPDU_START_THRESH 20
+#define WCN36XX_MAX_SCAN_SSIDS 9
+#define WCN36XX_MAX_SCAN_IE_LEN 500
+
extern unsigned int wcn36xx_dbg_mask;
enum wcn36xx_debug_mask {
@@ -212,6 +215,12 @@ struct wcn36xx {
spinlock_t hal_ind_lock;
struct list_head hal_ind_queue;
+ struct work_struct scan_work;
+ struct cfg80211_scan_request *scan_req;
+ int scan_freq;
+ int scan_band;
+ struct mutex scan_lock;
+
/* DXE channels */
struct wcn36xx_dxe_ch dxe_tx_l_ch; /* TX low */
struct wcn36xx_dxe_ch dxe_tx_h_ch; /* TX high */
--
2.5.0
^ permalink raw reply related
* [PATCH] brcmfmac: update beacon IE when bss up and clear when stopped
From: Wright Feng @ 2016-11-15 2:23 UTC (permalink / raw)
To: arend.vanspriel, franky.lin, hante.meuleman, pieterpg, kvalo
Cc: brcm80211-dev-list.pdl, linux-wireless, Chi-Hsien Lin,
wright.feng
Firmware doesn't update beacon vendor IEs when bss is down, so move brcmf_config_ap_mgmt_ie after BSS up. And host driver should clear IEs when AP stopped so that the IEs in host side will be synced with in firmware side.
Signed-off-by: Wright Feng <wright.feng@cypress.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index b777e1b..d022605 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -4578,8 +4578,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
brcmf_configure_opensecurity(ifp);
}
- brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
-
/* Parameters shared by all radio interfaces */
if (!mbss) {
if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
@@ -4708,6 +4706,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
WARN_ON(1);
}
+ brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
brcmf_net_setcarrier(ifp, true);
@@ -4764,6 +4763,8 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
if (err < 0)
brcmf_err("BRCMF_C_UP error %d\n", err);
+
+ brcmf_vif_clear_mgmt_ies(ifp->vif);
} else {
bss_enable.bsscfgidx = cpu_to_le32(ifp->bsscfgidx);
bss_enable.enable = cpu_to_le32(0);
--
2.1.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox