* [PATCH 01/53] wireless-regdb: AU, Australia - enable VHT80
From: Luis R. Rodriguez @ 2013-07-17 2:17 UTC (permalink / raw)
To: linville; +Cc: wireless-regdb, linux-wireless, Luis R. Rodriguez
In-Reply-To: <1374027522-18488-1-git-send-email-mcgrof@do-not-panic.com>
From: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
This enables 80 MHz bandwidth usage on all 5 GHz
frequencies and updates the max EIRP. This also adds
a new DFS 5 GHz band: 5490 - 5710 MHz.
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
db.txt | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/db.txt b/db.txt
index c5861b8..0e7794e 100644
--- a/db.txt
+++ b/db.txt
@@ -53,9 +53,10 @@ country AT: DFS-ETSI
country AU:
(2402 - 2482 @ 40), (N/A, 20)
- (5170 - 5250 @ 40), (3, 23)
- (5250 - 5330 @ 40), (3, 23), DFS
- (5735 - 5835 @ 40), (3, 30)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
country AW:
(2402 - 2482 @ 40), (N/A, 20)
--
1.7.10.4
^ permalink raw reply related
* [PATCH 00/53] wireless-regdb: latest updates
From: Luis R. Rodriguez @ 2013-07-17 2:17 UTC (permalink / raw)
To: linville; +Cc: wireless-regdb, linux-wireless, Luis R. Rodriguez
From: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
I saw one comment posted about the Indonesia patch, I fixed that.
I also then ran some sanity tests with a new reglib addition
wich I recently posted. This helped find two cases which
required disabling VHT80 for two countries on a specific band.
One was for US for 5690 and another for TW for 5290. In both cases
the reason is due to the fact that the only way to use VHT80 is
to combine two frequency ranges together that are contiguous and
apply the most restrictive band rules for that range. We don't support
this yet so just disable VHT80 in both cases. In the US case this
also seems to be the preferred ruling.
This now goes out in patch form.
Luis R. Rodriguez (53):
wireless-regdb: AU, Australia - enable VHT80
wireless-regdb: BR, Brazil - enable VHT80
wireless-regdb: CA, Canada - enable VHT80
wireless-regdb: HK, Hong Kong - enable VHT80
wireless-regdb: NZ, New Zealand - enable VHT80
wireless-regdb: AR, Argentina - enable VHT80
wireless-regdb: CO, Colombia - enable VHT80
wireless-regdb: GU, Guam - enable VHT80
wireless-regdb: MX, Mexico - enable VHT80
wireless-regdb: PE, Peru - enable VHT80
wireless-regdb: PH, Philippines - enable VHT80
wireless-regdb: PR, Puerto Rico - enable VHT80
wireless-regdb: SA, Saudi Arabia - enable VHT80
wireless-regdb: SG, Singapore - enable VHT80
wireless-regdb: ZA, South Africa - enable VHT80
wireless-regdb: TH, Thailand - enable VHT80
wireless-regdb: AE, United Arab Emirates - enable VHT80
wireless-regdb: VN, Vietnam - enable VHT80
wireless-regdb: AT, Austria - enable VHT80
wireless-regdb: FR, France - enable VHT80
wireless-regdb: DE, Germany - enable VHT80
wireless-regdb: GB, United Kingdom - enable VHT80
wireless-regdb: BE, Belgium - enable VHT80
wireless-regdb: CZ, Czech Republic - enable VHT80
wireless-regdb: DK, Denmark - enable VHT80
wireless-regdb: FI, Finland - enable VHT80
wireless-regdb: GR, Greece- enable VHT80
wireless-regdb: IE, Ireland - enable VHT80
wireless-regdb: IT, Italy - enable VHT80
wireless-regdb: LU, Luxembourg - enable VHT80
wireless-regdb: NL, Netherlands - enable VHT80
wireless-regdb: PL, Poland - enable VHT80
wireless-regdb: PT, Portugal - enable VHT80
wireless-regdb: SK, Slovakia - enable VHT80
wireless-regdb: ES, Spain - enable VHT80
wireless-regdb: SE, Sweden - enable VHT80
wireless-regdb: CH, Switzerland - enable VHT80
wireless-regdb: TR, Turkey - enable VHT80
wireless-regdb: CN, China - enable VHT80
wireless-regdb: enable VHT80 and VHT160 for JP
wireless-regdb: US, United States - enable VHT80
wireless-regdb: ID, Indonesia - enable 5 GHz and VHT80
wireless-regdb: IL, Isreal - enable VHT80
wireless-regdb: KW, Kuwait - enable VHT80
wireless-regdb: MY, Malaysia - enable VHT80
wireless-regdb: MA, Morocco - enable 5 GHz and VHT80
wireless-regdb: enable HT40 in RU - Russian Federation
wireless-regdb: KR, Republic of Korea - enable VHT80
wireless-regdb: TW, Taiwan - enable VHT80
wireless-regdb: enable VHT80 when world roaming
wireless-regdb: add 802.11ad 60 GHz channels 1..3 to world regdom
wireless-regdb: CR, Costa Rica - enable VHT80
wireless-regdb: EC, Ecauador - enable VHT80
db.txt | 316 +++++++++++++++++++++++++++++++++++-----------------------------
1 file changed, 173 insertions(+), 143 deletions(-)
--
1.7.10.4
^ permalink raw reply
* [PATCH] reglib: add reglib_is_valid_rd() and verify data upon build
From: Luis R. Rodriguez @ 2013-07-17 1:32 UTC (permalink / raw)
To: linville; +Cc: wireless-regdb, linux-wireless, Luis R. Rodriguez
From: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
This will verify the sanity of a regulatory domain upon build
time. This is useful if you are making modifications to
wireless-regdb and need to verify the regulatory domains
won't be rejected by a similar checker. In the case of the
Linux kernel regulatory domain data structures that get
a complaint would have been rejected completely.
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
regdbdump.c | 5 +++++
reglib.c | 16 ++++++++++++++++
reglib.h | 10 ++++++++++
3 files changed, 31 insertions(+)
diff --git a/regdbdump.c b/regdbdump.c
index cc7eb85..bb83af9 100644
--- a/regdbdump.c
+++ b/regdbdump.c
@@ -8,6 +8,11 @@ static void reglib_regdbdump(const struct reglib_regdb_ctx *ctx)
unsigned int idx = 0;
reglib_for_each_country(rd, idx, ctx) {
+ if (!reglib_is_valid_rd(rd)) {
+ fprintf(stderr, "country %.2s: invalid\n", rd->alpha2);
+ free((struct ieee80211_regdomain *) rd);
+ continue;
+ }
reglib_print_regdom(rd);
free((struct ieee80211_regdomain *) rd);
}
diff --git a/reglib.c b/reglib.c
index 224821b..64584f4 100644
--- a/reglib.c
+++ b/reglib.c
@@ -427,6 +427,22 @@ static int is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
return 1;
}
+int reglib_is_valid_rd(const struct ieee80211_regdomain *rd)
+{
+ const struct ieee80211_reg_rule *reg_rule = NULL;
+ unsigned int i;
+
+ if (!rd->n_reg_rules)
+ return 0;
+
+ for (i = 0; i < rd->n_reg_rules; i++) {
+ reg_rule = &rd->reg_rules[i];
+ if (!is_valid_reg_rule(reg_rule))
+ return 0;
+ }
+ return 1;
+}
+
/*
* Helper for reglib_intersect_rds(), this does the real
* mathematical intersection fun
diff --git a/reglib.h b/reglib.h
index 57082fe..7a586a3 100644
--- a/reglib.h
+++ b/reglib.h
@@ -150,6 +150,16 @@ reglib_get_rd_idx(unsigned int idx, const struct reglib_regdb_ctx *ctx);
const struct ieee80211_regdomain *
reglib_get_rd_alpha2(const char *alpha2, const char *file);
+/**
+ * reglib_is_valid_rd - validate regulatory domain data structure
+ *
+ * @rd: regulatory domain data structure to validate
+ *
+ * You can use this to validate regulatory domain data structures
+ * for possible inconsistencies.
+ */
+int reglib_is_valid_rd(const struct ieee80211_regdomain *rd);
+
/* reg helpers */
void reglib_print_regdom(const struct ieee80211_regdomain *rd);
struct ieee80211_regdomain *
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH] reglib: Validate all structure and array lengths
From: Luis R. Rodriguez @ 2013-07-17 1:31 UTC (permalink / raw)
To: Ben Hutchings, linux-wireless
Cc: wireless-regdb@lists.infradead.org, alexandre
In-Reply-To: <1372636171.5155.56.camel@deadeye.wl.decadent.org.uk>
On Sun, Jun 30, 2013 at 4:49 PM, Ben Hutchings <ben@decadent.org.uk> wrote:
> Add checks that:
> - Signature length does not exceed the file length (this was already
> checked, but did not account for signature lengths greater than 2 GB)
> - Database length is long enough for all structures we expect in it
> - Array length calculations will not overflow
>
> To keep these checks simple, change the types of array length and index
> variables to unsigned int (must be at least 32-bit, matching the file
> format) and the types of byte-length variables to size_t.
>
> Alexandre Rebert <alexandre@cmu.edu> reported and provided a test case
> for the signature length issue; the others I found by inspection.
>
> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Thanks! Despite the fact you didn't resend for a wider review and I
would have preferred this split up into a few patches this has been
sitting on wireless-regdb for a while, so after my review I just
applied and pushed. Thanks again!
Luis
> ---
> reglib.c | 58 +++++++++++++++++++++++++++++++++++++++++-----------------
> reglib.h | 5 +++--
> 2 files changed, 44 insertions(+), 19 deletions(-)
>
> diff --git a/reglib.c b/reglib.c
> index c4d00f8..224821b 100644
> --- a/reglib.c
> +++ b/reglib.c
> @@ -10,6 +10,7 @@
> #include <stdbool.h>
> #include <unistd.h>
> #include <string.h>
> +#include <limits.h>
>
> #include <arpa/inet.h> /* ntohl */
>
> @@ -37,10 +38,16 @@
> #include "keys-gcrypt.c"
> #endif
>
> -void *reglib_get_file_ptr(uint8_t *db, int dblen, int structlen, uint32_t ptr)
> +void *
> +reglib_get_file_ptr(uint8_t *db, size_t dblen, size_t structlen, uint32_t ptr)
> {
> uint32_t p = ntohl(ptr);
>
> + if (structlen > dblen) {
> + fprintf(stderr, "Invalid database file, too short!\n");
> + exit(3);
> + }
> +
> if (p > dblen - structlen) {
> fprintf(stderr, "Invalid database file, bad pointer!\n");
> exit(3);
> @@ -49,6 +56,17 @@ void *reglib_get_file_ptr(uint8_t *db, int dblen, int structlen, uint32_t ptr)
> return (void *)(db + p);
> }
>
> +static size_t
> +reglib_array_len(size_t baselen, unsigned int elemcount, size_t elemlen)
> +{
> + if (elemcount > (SIZE_MAX - baselen) / elemlen) {
> + fprintf(stderr, "Invalid database file, count too large!\n");
> + exit(3);
> + }
> +
> + return baselen + elemcount * elemlen;
> +}
> +
> /*
> * reglib_verify_db_signature():
> *
> @@ -59,7 +77,7 @@ void *reglib_get_file_ptr(uint8_t *db, int dblen, int structlen, uint32_t ptr)
> */
>
> #ifdef USE_OPENSSL
> -int reglib_verify_db_signature(uint8_t *db, int dblen, int siglen)
> +int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen)
> {
> RSA *rsa;
> uint8_t hash[SHA_DIGEST_LENGTH];
> @@ -118,7 +136,7 @@ out:
> #endif /* USE_OPENSSL */
>
> #ifdef USE_GCRYPT
> -int reglib_verify_db_signature(uint8_t *db, int dblen, int siglen)
> +int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen)
> {
> gcry_mpi_t mpi_e, mpi_n;
> gcry_sexp_t rsa, signature, data;
> @@ -180,7 +198,7 @@ out:
> #endif /* USE_GCRYPT */
>
> #if !defined(USE_OPENSSL) && !defined(USE_GCRYPT)
> -int reglib_verify_db_signature(uint8_t *db, int dblen, int siglen)
> +int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen)
> {
> return 1;
> }
> @@ -220,7 +238,7 @@ const struct reglib_regdb_ctx *reglib_malloc_regdb_ctx(const char *regdb_file)
> return NULL;
> }
>
> - ctx->header = reglib_get_file_ptr(ctx->db, ctx->dblen,
> + ctx->header = reglib_get_file_ptr(ctx->db, ctx->real_dblen,
> sizeof(struct regdb_file_header),
> 0);
> header = ctx->header;
> @@ -232,12 +250,13 @@ const struct reglib_regdb_ctx *reglib_malloc_regdb_ctx(const char *regdb_file)
> goto err_out;
>
> ctx->siglen = ntohl(header->signature_length);
> - /* The actual dblen does not take into account the signature */
> - ctx->dblen = ctx->real_dblen - ctx->siglen;
>
> - if (ctx->dblen <= sizeof(*header))
> + if (ctx->siglen > ctx->real_dblen - sizeof(*header))
> goto err_out;
>
> + /* The actual dblen does not take into account the signature */
> + ctx->dblen = ctx->real_dblen - ctx->siglen;
> +
> /* verify signature */
> if (!reglib_verify_db_signature(ctx->db, ctx->dblen, ctx->siglen))
> goto err_out;
> @@ -272,7 +291,7 @@ void reglib_free_regdb_ctx(const struct reglib_regdb_ctx *regdb_ctx)
> free(ctx);
> }
>
> -static void reg_rule2rd(uint8_t *db, int dblen,
> +static void reg_rule2rd(uint8_t *db, size_t dblen,
> uint32_t ruleptr, struct ieee80211_reg_rule *rd_reg_rule)
> {
> struct regdb_file_reg_rule *rule;
> @@ -303,18 +322,21 @@ country2rd(const struct reglib_regdb_ctx *ctx,
> {
> struct regdb_file_reg_rules_collection *rcoll;
> struct ieee80211_regdomain *rd;
> - int i, num_rules, size_of_rd;
> + unsigned int i, num_rules;
> + size_t size_of_rd;
>
> rcoll = reglib_get_file_ptr(ctx->db, ctx->dblen, sizeof(*rcoll),
> country->reg_collection_ptr);
> num_rules = ntohl(rcoll->reg_rule_num);
> /* re-get pointer with sanity checking for num_rules */
> rcoll = reglib_get_file_ptr(ctx->db, ctx->dblen,
> - sizeof(*rcoll) + num_rules * sizeof(uint32_t),
> - country->reg_collection_ptr);
> + reglib_array_len(sizeof(*rcoll), num_rules,
> + sizeof(uint32_t)),
> + country->reg_collection_ptr);
>
> - size_of_rd = sizeof(struct ieee80211_regdomain) +
> - num_rules * sizeof(struct ieee80211_reg_rule);
> + size_of_rd = reglib_array_len(sizeof(struct ieee80211_regdomain),
> + num_rules,
> + sizeof(struct ieee80211_reg_rule));
>
> rd = malloc(size_of_rd);
> if (!rd)
> @@ -468,7 +490,8 @@ struct ieee80211_regdomain *
> reglib_intersect_rds(const struct ieee80211_regdomain *rd1,
> const struct ieee80211_regdomain *rd2)
> {
> - int r, size_of_regd;
> + int r;
> + size_t size_of_regd;
> unsigned int x, y;
> unsigned int num_rules = 0, rule_idx = 0;
> const struct ieee80211_reg_rule *rule1, *rule2;
> @@ -506,8 +529,9 @@ reglib_intersect_rds(const struct ieee80211_regdomain *rd1,
> if (!num_rules)
> return NULL;
>
> - size_of_regd = sizeof(struct ieee80211_regdomain) +
> - ((num_rules + 1) * sizeof(struct ieee80211_reg_rule));
> + size_of_regd = reglib_array_len(sizeof(struct ieee80211_regdomain),
> + num_rules + 1,
> + sizeof(struct ieee80211_reg_rule));
>
> rd = malloc(size_of_regd);
> if (!rd)
> diff --git a/reglib.h b/reglib.h
> index 86087e3..57082fe 100644
> --- a/reglib.h
> +++ b/reglib.h
> @@ -112,8 +112,9 @@ static inline uint32_t reglib_min(uint32_t a, uint32_t b)
> return (a > b) ? b : a;
> }
>
> -void *reglib_get_file_ptr(uint8_t *db, int dblen, int structlen, uint32_t ptr);
> -int reglib_verify_db_signature(uint8_t *db, int dblen, int siglen);
> +void *
> +reglib_get_file_ptr(uint8_t *db, size_t dblen, size_t structlen, uint32_t ptr);
> +int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen);
>
> /**
> * reglib_malloc_regdb_ctx - create a regdb context for usage with reglib
>
^ permalink raw reply
* Re: [RFC 00/53] wireless-regdb: mostly VHT80 updates
From: Luis R. Rodriguez @ 2013-07-16 23:54 UTC (permalink / raw)
To: John W. Linville
Cc: wireless-regdb@lists.infradead.org, linux-wireless,
Luis R. Rodriguez
In-Reply-To: <CAB=NE6WmcGs6u8ZCrWXcKQe=MsQk_C7R7i+x1V-cDbjQ+A8d-w@mail.gmail.com>
On Tue, Jul 16, 2013 at 1:18 PM, Luis R. Rodriguez
<mcgrof@do-not-panic.com> wrote:
> On Wed, Jul 3, 2013 at 6:03 PM, Luis R. Rodriguez
> <mcgrof@do-not-panic.com> wrote:
>> From: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
>>
>> Here's a series of updates for wireless-regdb. Most of this is
>> to just enable VHT80 support to enable support for 802.11ac
>> where this has been verified to be usable. I cannot meet the
>> criteria of providing full documentation for sources for all
>> patches, only a few ones so what I recommend for the rest is
>> to let this sit on the list for a bit and I'd hope after
>> review if no one spots any issues I'd hope we can merge this.
>>
>> I reviewed the idea of vendor namespaces on wireless-regdb
>> and at least through review with pkgadd on IRC we concluded
>> its best to try to take this approach instead of encouraging
>> divergence due to any lack of full source documentation or
>> inability to provide such documentation for whatever reason.
>> This seems to be better than not getting any updates at all
>> and keeps vendors hopefully encouraged to push changes upstream.
>
> I saw one comment addressing a typo on ID, I've fixed that. If there
> are no complaints can we merge these to get VHT80?
Please hold off on these for a bit. I need to test one more thing.
Luis
^ permalink raw reply
* Re: [PATCH 3/3] [RFC] cfg80211: Enable GO operation on additional channels
From: Luis R. Rodriguez @ 2013-07-16 20:57 UTC (permalink / raw)
To: Peer, Ilan
Cc: Spinadel, David, linux-wireless,
wireless-regdb@lists.infradead.org, Jouni Malinen, Ginsburg, Noam,
Perelmooter, Liraz, Shalev, Oz, Michael Green
In-Reply-To: <CB3B3D4774441E42AA3EA0E1BA8230A01AD2DFC5@HASMSX106.ger.corp.intel.com>
On Wed, Jul 10, 2013 at 3:47 AM, Peer, Ilan <ilan.peer@intel.com> wrote:
>> Are you aware of UNII-1, UNII-2, UNII-2E, UNII-3 are specific world regulatory
>> language bands? When I last tried to look for a clear definition I could not find
>> a clear definition of them and its why on the ath module on for QCA modules I
>> state "we call these" in reference to the UNII nomenclature. If we can get a
>> clear resource for its definition that would help here.
>>
>
> Maybe these link will help.
> http://www.gpo.gov/fdsys/pkg/CFR-2010-title47-vol1/xml/CFR-2010-title47-vol1-part15.xml#seqnum15.403
> http://hraunfoss.fcc.gov/edocs_public/attachmatch/FCC-13-22A1.pdf
>
> Anyway, I will use your ''we call these" notation as well :)
No no, this is good, its just United States / FCC biased and I hadn't
seen the documentation you provided before. This confirms these are
official terms but still just US / FCC biased. My point was that we
should be careful to not make global statements on regulatory code
about things that are not global. If we know only the FCC calls this
UNII well lets document that and provide the reference you supplied. I
anticipated having to deal with special case regulatory code outside
of of what CRDA / wireless-regdb provides -- given that CRDA /
wireless-regdb were meant to be more RF agnostic anyway.
Given that other vendors may also want to get the UNII band can you
stuff instead cfg80211_get_unii_band() into reg.c and do the #ifdef
properly with the Kconfig, and export it as well, as well as document
it properly providing the reference you mentioned.
>> > + * 1. Indoor only: a GO can be operational on such a channel, iff there is
>> > + * clear assessment that the platform device is indoor.
>> > + * 2. Concurrent GO: a GO can be operational on such a channel, iff there is
>> an
>> > + * additional station interface connected to an AP on this channel.
>> > + *
>> > + * TODO: The function is too permissive, as it does not verify the
>> > + platform
>> > + * device type is indeed indoor, or that the AP is indoor/AC powered.
>>
>> So to do this properly we need an eventual userspace API to throw to
>> kernelspace if we are AC powered? We'll need this to enhance this routine
>> here?
>>
>
> Not sure about this point. I prefer leaving the exact knowledge of the device type, being AC Powered or not (and which type of AC power) etc. out side of the kernel. The approach I chose with this patch was to only allow to start a GO on such a channel, making the basic verification done above, assuming that the user space component guarantees that all the full restrictions are satisfied.
Fair enough. Seems we just need to zero in now on the requirement or
not on the extra flag you suggested.
>> In the meantime, while you get all your patch sets properly developed I'd
>> recommend to define the code returning false there strictly or perhaps for any
>> flag on the channel requiring DFS / no-ibss, or passive scan. The stricter case,
>> defining false always, seems to be what you are suggesting here.
>
> I do not think that this is needed here. Returning false, means that the code should test if the PASSIVE_SCAN and NO_IBSS are not set on the channel we want to start beaconing on.
>
>> Do you have a white list that can exclude some channels for now globally or
>> somehow as all this lines up?
>>
>
> Note sure I understood what you are looking for. Can you please clarify this point?
It was unclear for what exact channels you needed to deal with here.
Given review so far wouldn't it just be DFS flagged channels on some
UNII bands ? Then again if the indoor flag needs to be pegged to to a
specific UNII band and we can do that on wireless-regdb do we even
need the UNII band check routine helper?
Luis
^ permalink raw reply
* Re: [PATCH 1/3] [RFC] cfg80211: Add indoor only and GO concurrent channel attributes
From: Luis R. Rodriguez @ 2013-07-16 20:43 UTC (permalink / raw)
To: Peer, Ilan
Cc: wireless-regdb@lists.infradead.org, linux-wireless,
Spinadel, David, Ginsburg, Noam, Perelmooter, Liraz, Shalev, Oz,
Michael Green
In-Reply-To: <CB3B3D4774441E42AA3EA0E1BA8230A01AD2DF7B@HASMSX106.ger.corp.intel.com>
On Wed, Jul 10, 2013 at 3:43 AM, Peer, Ilan <ilan.peer@intel.com> wrote:
>> On Tue, Jul 2, 2013 at 5:28 AM, Ilan Peer <ilan.peer@intel.com> wrote:
>> > From: David Spinadel <david.spinadel@intel.com>
>> >
>> > The FCC are clarifying some soft configuration requirements, which
>> > among other includes the following:
>> >
>> > 1. Concurrent GO operation, where devices may support WFD in
>> > bands where an authorized master (for example with DFS and
>> > DFS and radar detection capability in the UNII band) is operating.
>>
>> Is WFD WiFi Display? Is there any strict relationship here to WFD and GO and
>> regulatory or is WFD just a use case example? Are you indicating that the FCC
>> is making special rules for cases in specific bands where GO *can* co-exist with
>> other GO devices ?
>
> WFD is WiFi direct in this context. I do not think that the FCC are making special rules only for GO specific scenarios but a more general approach where "compliance may be achieved under the guidance of an authorized master". The WFD/P2P GO case is only an example.
OK then I think cullular base station regulatory hints might be
another example. In fact I believe I am looking at the information you
might be using as reference. I am looking at public draft edit for FCC
KDB 594280:
https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
The original KDB:
http://transition.fcc.gov/oet/ea/presentations/files/apr11/3b.SoftwareConfigurationControl-RDJS.pdf
Specifically in the above document, the draft edit, I am looking at
page 12. That actually references WiFi Direct precisely and considers
the case that a GO may need to move out of its channel if its master
device its using to configure itself also switches channels. Given
that cellular base station hints could also technically be used this
also would need to be considered for cellular base stations. But also
note on page 14 it states clearly:
"Mobile Country Codes (MCC) or Mobile Network Codes
(MNC) are not acceptable for programming host
compliance"
So it seems cellular base station hints are simply not allowed by the
FCC (unless specific approval is requested / revised). Even if the FCC
allowed for it I believe an API would need to be provided should
cellular base stations have a case where they may stop operating as
well similar to DFS.
BTW in future iterations of patches I'd appreciate if you can include
the above references to documentation given that we've pulled them up
now.
>> You annotate that this is somehow related to DFS, are the GO concurrent rules
>> that the FCC is defining only applicable to DFS frequency ranges? If so would it
>> suffice to only use DFS flag ? Or are there other special cases beyond DFS
>> frequency ranges that the FCC is creating special handling?
>>
>
> DFS was given here as an example. Generally, I think that the changes that the FCC are making are targeting various scenarios and various RF devices (for example those defined in part 15 of CFR title 47).
OK thanks. Things are clear now that I see the document that you might
be referring to.
>> Apart from the FCC are you aware of special cases handling for other
>> regulatory bodies at this point?
>
> Not that I'm aware of. Adding some more people that might know more.
Hey folks, anyone? :)
>> Note that we have already these on regdb.h from CRDA:
>>
>>
>> /*
>> * The Linux map defined in <linux/uapi/nl80211.h> enum
>> nl80211_reg_rule_flags */ enum reg_rule_flags {
>> RRF_NO_OFDM = 1<<0, /* OFDM modulation not allowed */
>> RRF_NO_CCK = 1<<1, /* CCK modulation not allowed */
>> RRF_NO_INDOOR = 1<<2, /* indoor operation not allowed */
>> RRF_NO_OUTDOOR = 1<<3, /* outdoor operation not allowed */
>> RRF_DFS = 1<<4, /* DFS support is required to be
>> * used */
>> RRF_PTP_ONLY = 1<<5, /* this is only for Point To Point
>> * links */
>> RRF_PTMP_ONLY = 1<<6, /* this is only for Point To Multi
>> * Point links */
>> RRF_PASSIVE_SCAN = 1<<7, /* passive scan is required */
>> RRF_NO_IBSS = 1<<8, /* IBSS is not allowed */
>> };
>>
>> Historically we don't distinguish then a type of 802.11 device that initiates
>> radiation except for the NO_IBSS rule, but that rule can be treated more as
>> legacy given that the intent and motivation behind that was that some ODMs
>> simply preferred an interpretation of regulatory rules and we *currently* don't
>> use that in much places other than custom regulatory domains defined in the
>> kernel. The PTP_ONLY and PTMP_ONLY are example other rules that could
>> potentially have been used but to this day we haven't found a use case for it
>> given that typical 802.11 devices are PTMP.
>>
>> I mention the NO_IBSS case as I'd like to try to avoid adding GO specific flag if
>> we can figure out a way to make this more generic. At this point for example I
>> think a more appropriate flag is in place:
>>
>
> Actually, this should be a GO only flag, meaning that such relaxation should not be valid for soft AP, IBSS or mesh. The intention here is limit the extend of the cell, and prevent daisy chain scenarios (assume that you allow a soft AP on such a channel and that a client associated to it, and then that device can also start a soft AP on the channel ....). Anyway, I'll need to have another look at this (might be permissible for IBSS ...)
Based on the documentation I reviewed and your proposal it'd seem to
me that we can distinguish GO on the upper layers and determine if a
channel is DFS or not by just the DFS flag. The next hint you'd need
is if the GO got regulatory information from a master somehow, no?
That is I am not seeing a need for a new flag at this point in
wireless-regdb, given also I mentioned another type of case for
regulatory hints technically possible (cellular base station hints but
it seems only allowed with exceptional review by the FCC).
I take it what you want to enable here is GO operation on DFS channels
and use country IEs to determine if you can use GO, but if you do have
GO enabled then you'd want hooks to not daisy chain, ack?
>> > 2. Indoor operation, where in bands requiring indoor operation, the
>> > device must be programmed to detect indoor operation, or
>> > - Device must be connected to AC Power
>>
>> Does anyone know if the FCC considers "indoor" if we power a device through
>> the car on AC power through a converter ? Are we willing to ignore that corner
>> case?
>
> No. AC power means "mains" and not through portable DC converters (see slide 12 in https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn= 528122). It would be up to the user space to identify the device type etc. and identify if this a truly AC powered AP.
OK thanks for the clarification. I wonder if we can distinguish
between the two in userspace today. I'm happy to start pegging
frequency ranges as indoor-only on wireless-regdb even if we don't
have the userspace APIs to annotate when a device is indoor or not
yet. Patches welcomed then.
>> > - Device must be under the control of a local master that is acting
>>
>> Interesting, so some APIs would be defined, I take it on hostapd to do the
>> proper callbacks to 'slave' type of devices that depend on the local master(s). I
>> could envision this being implemented on hostapd by expanding the AP
>> interface type and associating 'slave' devices and callbacks for updates on AP
>> device updates (channel changes, and so on). Is this work being planned?
>
> Yes. We have plans to incorporate more logic to hostap (currently into wpa_supplicant for P2P use cases).
Sweet.
Luis
^ permalink raw reply
* Re: [RFC 00/53] wireless-regdb: mostly VHT80 updates
From: Luis R. Rodriguez @ 2013-07-16 20:18 UTC (permalink / raw)
To: John W. Linville
Cc: wireless-regdb@lists.infradead.org, linux-wireless,
Luis R. Rodriguez
In-Reply-To: <1372899889-19183-1-git-send-email-mcgrof@do-not-panic.com>
On Wed, Jul 3, 2013 at 6:03 PM, Luis R. Rodriguez
<mcgrof@do-not-panic.com> wrote:
> From: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
>
> Here's a series of updates for wireless-regdb. Most of this is
> to just enable VHT80 support to enable support for 802.11ac
> where this has been verified to be usable. I cannot meet the
> criteria of providing full documentation for sources for all
> patches, only a few ones so what I recommend for the rest is
> to let this sit on the list for a bit and I'd hope after
> review if no one spots any issues I'd hope we can merge this.
>
> I reviewed the idea of vendor namespaces on wireless-regdb
> and at least through review with pkgadd on IRC we concluded
> its best to try to take this approach instead of encouraging
> divergence due to any lack of full source documentation or
> inability to provide such documentation for whatever reason.
> This seems to be better than not getting any updates at all
> and keeps vendors hopefully encouraged to push changes upstream.
I saw one comment addressing a typo on ID, I've fixed that. If there
are no complaints can we merge these to get VHT80?
Luis
^ permalink raw reply
* [RFC v2] wireless-regdb: ID, Indonesia - enable 5 GHz and VHT80
From: Luis R. Rodriguez @ 2013-07-16 20:07 UTC (permalink / raw)
To: linville; +Cc: wireless-regdb, linux-wireless, pstew, Luis R. Rodriguez
From: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
Pursuant to:
http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf,
provide a 5GHz rule for Indonesian regulatory domain. QCA has
also verified VHT80 can be enabled. Patch originally posted by
Paul Stewart <pstew@chromium.org>, I just modified to enable 80 MHz
bandwidth.
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
---
This v2 changes the bandwidth to 80 as was intended with the first
patch.
db.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/db.txt b/db.txt
index 0ebb934..8356d5d 100644
--- a/db.txt
+++ b/db.txt
@@ -380,7 +380,9 @@ country HU: DFS-ETSI
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
country ID:
+ # ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
(2402 - 2482 @ 40), (N/A, 20)
+ (5735 - 5815 @ 80), (N/A, 20)
country IE: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
--
1.7.10.4
^ permalink raw reply related
* Re: [BUG] 3.10 regression: hang on suspend
From: Ortwin Glück @ 2013-07-16 18:23 UTC (permalink / raw)
To: Arend van Spriel; +Cc: Stanislaw Gruszka, linux-kernel, linux-wireless
In-Reply-To: <51E51712.4020609@broadcom.com>
Without NetworkManager, no X, on console and with plain jane wpa_supplicant I do
echo mem > /sys/power state
After that, it still responds to keyboard events: I can switch VT and type on
the consoles, but I can not login on a different VT (pressing Enter after the
username doesn't return). So I guess tasks have been frozen, but it hangs in
stopping devices.
settings for pm_test:
devices: same behviour as above
freezer: works as expected (stops tasks; sleeps; resumes tasks)
Nothing in the logs. How can I enable more log?
Ortwin
^ permalink raw reply
* Re: [PATCH 3.11] mac80211/minstrel: fix NULL pointer dereference issue
From: Johannes Berg @ 2013-07-16 14:48 UTC (permalink / raw)
To: Felix Fietkau; +Cc: linux-wireless, krzysiek
In-Reply-To: <1373891706-1071-1-git-send-email-nbd@openwrt.org>
On 2013-07-15 15:35, Felix Fietkau wrote:
> When priv_sta == NULL, mi->prev_sample is dereferenced too early. Move
> the assignment further down, after the rate_control_send_low call.
Applied.
johannes
^ permalink raw reply
* Re: Power saving features for iwl4965
From: Pedro Francisco @ 2013-07-16 11:02 UTC (permalink / raw)
To: Stanislaw Gruszka; +Cc: Tino Keitel, ML linux-wireless
In-Reply-To: <20130716102743.GA8321@redhat.com>
On Tue, Jul 16, 2013 at 11:27 AM, Stanislaw Gruszka <sgruszka@redhat.com> wrote:
> You can provide me logs with disable_hw_scan=0, if you manage to
> trigger a Microcode error.
I can't trigger the microcode error with the debug. The firmware
however gets corrupted and reloading the module does not fix it
(firmware validation fails until I restart) -- curiously after a
'power info' RXON (? or similar, can't access the logs now) is sent to
the card.
I'll test again tomorrow.
^ permalink raw reply
* [PATCH 1/2] cfg80211: add beacon measurements command
From: Johannes Berg @ 2013-07-16 10:45 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <1373971517-315-1-git-send-email-johannes@sipsolutions.net>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This new nl80211 command allow a user space application to
instruct the WiFi stack to let all the beacons through so
that measurements can be conducted on these beacons (i.e.
RSSI etc...)
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/cfg80211.h | 12 ++++++++++++
include/uapi/linux/nl80211.h | 10 ++++++++++
net/wireless/nl80211.c | 32 +++++++++++++++++++++++++++++++-
net/wireless/rdev-ops.h | 13 +++++++++++++
net/wireless/trace.h | 17 +++++++++++++++++
5 files changed, 83 insertions(+), 1 deletion(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index aeaf6df..019e256 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2139,6 +2139,10 @@ struct cfg80211_update_ft_ies_params {
* @crit_proto_stop: Indicates critical protocol no longer needs increased link
* reliability. This operation can not fail.
* @set_coalesce: Set coalesce parameters.
+ *
+ * @beacon_measurement: Start / stops the beacon measurement. When enabled,
+ * beacons should be let through cfg80211 to proceed to measurements (e.g.
+ * RSSI analysis).
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2376,6 +2380,10 @@ struct cfg80211_ops {
struct wireless_dev *wdev);
int (*set_coalesce)(struct wiphy *wiphy,
struct cfg80211_coalesce *coalesce);
+
+ int (*beacon_measurement)(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ bool state);
};
/*
@@ -2441,6 +2449,9 @@ struct cfg80211_ops {
* @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX.
* @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call.
* @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
+ * @WIPHY_FLAG_SUPPORTS_BEACON_MEAS: Device supports beacon measurements. Should
+ * be set when the device can let all the beacon through up to cfg80211
+ * to proceed to measurements (i.e. RSSI measurements).
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -2465,6 +2476,7 @@ enum wiphy_flags {
WIPHY_FLAG_OFFCHAN_TX = BIT(20),
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21),
WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22),
+ WIPHY_FLAG_SUPPORTS_BEACON_MEAS = BIT(23),
};
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index eb68735..1a5edad 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -676,6 +676,9 @@
* @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules.
* @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
*
+ * @NL80211_CMD_BEACON_MEASUREMENT: Indicates the beacon measurement is
+ * started / stopped. Disassociation should stop the measurements.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -841,6 +844,8 @@ enum nl80211_commands {
NL80211_CMD_GET_COALESCE,
NL80211_CMD_SET_COALESCE,
+ NL80211_CMD_BEACON_MEASUREMENT,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1469,6 +1474,9 @@ enum nl80211_commands {
*
* @NL80211_ATTR_COALESCE_RULE: Coalesce rule information.
*
+ * @NL80211_ATTR_BCON_MEAS_STATE: The state of the beacon measurements. This is
+ * a flag attribute.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1771,6 +1779,8 @@ enum nl80211_attrs {
NL80211_ATTR_COALESCE_RULE,
+ NL80211_ATTR_BCON_MEAS_STATE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 03d4ef9..c2b43b6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -349,6 +349,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
+ [NL80211_ATTR_BCON_MEAS_STATE] = { .type = NLA_FLAG, },
};
/* policy for the key attributes */
@@ -8646,6 +8647,27 @@ static int nl80211_crit_protocol_stop(struct sk_buff *skb,
return 0;
}
+static int nl80211_beacon_measurement(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+ bool state;
+
+
+ if (!rdev->ops->beacon_measurement ||
+ !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_BEACON_MEAS))
+ return -EOPNOTSUPP;
+
+ /* Relevant for associated mgd interfaces only */
+ if (wdev->iftype != NL80211_IFTYPE_STATION || !wdev->current_bss)
+ return -EOPNOTSUPP;
+
+ state = info->attrs[NL80211_ATTR_BCON_MEAS_STATE];
+
+ return rdev_beacon_measurement(rdev, wdev, state);
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -9361,7 +9383,15 @@ static struct genl_ops nl80211_ops[] = {
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
- }
+ },
+ {
+ .cmd = NL80211_CMD_BEACON_MEASUREMENT,
+ .doit = nl80211_beacon_measurement,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 9f15f0a..e5b0efb 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -923,4 +923,17 @@ static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev,
trace_rdev_return_void(&rdev->wiphy);
}
+static inline int
+rdev_beacon_measurement(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev, bool state)
+{
+ int ret;
+
+ trace_rdev_beacon_measurement(&rdev->wiphy, wdev, state);
+ ret = rdev->ops->beacon_measurement(&rdev->wiphy, wdev, state);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+
+ return ret;
+}
+
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 09af6eb..5f6e7f0 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1841,6 +1841,23 @@ TRACE_EVENT(rdev_crit_proto_stop,
WIPHY_PR_ARG, WDEV_PR_ARG)
);
+TRACE_EVENT(rdev_beacon_measurement,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, bool state),
+ TP_ARGS(wiphy, wdev, state),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ __field(bool, state)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ __entry->state = state;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT " %s",
+ WIPHY_PR_ARG, WDEV_PR_ARG, BOOL_TO_STR(__entry->state))
+);
+
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
--
1.8.0
^ permalink raw reply related
* [PATCH 0/2] beacon measurement (beacon filtering disable)
From: Johannes Berg @ 2013-07-16 10:45 UTC (permalink / raw)
To: linux-wireless
We have beacon filtering (to reduce host wakeups) in our device,
but for some measurement/debug purposes we need to turn it off.
This adds API for it -- comments welcome.
johannes
^ permalink raw reply
* [PATCH 2/2] mac80211: implement the beacon measurement ops
From: Johannes Berg @ 2013-07-16 10:45 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <1373971517-315-1-git-send-email-johannes@sipsolutions.net>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This tells the low-level driver to let all the beacons
through and update the data needed to conduct the
measurements.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/mac80211.h | 7 +++++++
net/mac80211/cfg.c | 14 ++++++++++++++
net/mac80211/driver-ops.h | 20 ++++++++++++++++++++
net/mac80211/trace.h | 23 +++++++++++++++++++++++
4 files changed, 64 insertions(+)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 3124036..fb8f6c6 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2634,6 +2634,10 @@ enum ieee80211_roc_type {
* driver's resume function returned 1, as this is just like an "inline"
* hardware restart. This callback may sleep.
*
+ * @beacon_measurement: Start or stop beacon measurement. When started, all the
+ * beacons must be let through and data for measurement should be set in
+ * &ieee80211_rx_status (rssi etc...).
+ *
* @ipv6_addr_change: IPv6 address assignment on the given interface changed.
* Currently, this is only called for managed or P2P client interfaces.
* This callback is optional; it must not sleep.
@@ -2819,6 +2823,9 @@ struct ieee80211_ops {
void (*restart_complete)(struct ieee80211_hw *hw);
+ int (*beacon_measurement)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, bool state);
+
#if IS_ENABLED(CONFIG_IPV6)
void (*ipv6_addr_change)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b82fff6..34b57a9 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3407,6 +3407,19 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
return ret;
}
+static int ieee80211_beacon_measurement(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ bool state)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION))
+ return -EINVAL;
+
+ return drv_beacon_measurement(local, sdata, state);
+}
+
#ifdef CONFIG_PM
static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled)
{
@@ -3492,4 +3505,5 @@ struct cfg80211_ops mac80211_config_ops = {
.get_et_strings = ieee80211_get_et_strings,
.get_channel = ieee80211_cfg_get_channel,
.start_radar_detection = ieee80211_start_radar_detection,
+ .beacon_measurement = ieee80211_beacon_measurement,
};
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index b931c96..7fbe57f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1060,6 +1060,26 @@ drv_set_default_unicast_key(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline int
+drv_beacon_measurement(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata, bool state)
+{
+ int ret = -EOPNOTSUPP;
+ check_sdata_in_driver(sdata);
+
+ trace_drv_beacon_measurement(local, sdata, state);
+
+ if (local->ops->beacon_measurement)
+ ret = local->ops->beacon_measurement(&local->hw, &sdata->vif,
+ state);
+ else
+ /* Driver advertises caps but doesn't implement the callback? */
+ WARN_ON_ONCE(1);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
#if IS_ENABLED(CONFIG_IPV6)
static inline void drv_ipv6_addr_change(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index c215fafd7..d41bbe2 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1887,6 +1887,29 @@ TRACE_EVENT(drv_set_default_unicast_key,
LOCAL_PR_ARG, VIF_PR_ARG, __entry->key_idx)
);
+TRACE_EVENT(drv_beacon_measurement,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ bool state),
+
+ TP_ARGS(local, sdata, state),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(bool, state)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->state = state;
+ ),
+
+ TP_printk(LOCAL_PR_FMT VIF_PR_FMT " state:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->state)
+);
+
TRACE_EVENT(api_radar_detected,
TP_PROTO(struct ieee80211_local *local),
--
1.8.0
^ permalink raw reply related
* Re: Power saving features for iwl4965
From: Stanislaw Gruszka @ 2013-07-16 10:27 UTC (permalink / raw)
To: Pedro Francisco; +Cc: Tino Keitel, ML linux-wireless
In-Reply-To: <CAJZjf_z=+QW_Y3yuz6nJ+muVA_6bGRut8EQ7fCopDqqj2Fn9Yw@mail.gmail.com>
On Thu, Jul 11, 2013 at 10:02:22PM +0100, Pedro Francisco wrote:
> > Pedro, please do the fallowing:
> >
> > Add this line in /etc/rsyslog.conf:
> > kern.* /var/log/kernel
> >
> > Restart rsyslog services:
> > # systemctl restart rsyslog.service
> >
> > Restart iwl3945 module with verbose debug enabled:
> > modprobe -r iwl3945
> > modprobe iwl3945 debug=0x47ffffff
> >
> > Reproduce the problem.
> >
> > Unload module:
> > modprobe -r iwl3945
> >
> > Then provide me generated /var/log/kernel file (compressed if needed).
>
> I seem only to be able to trigger it with disable_hw_scan=0, I need
> further testing with disable_hw_scan=1 (I use disable_hw_scan=0
> because it prevents me from getting disconnected from eduroam Cisco
> APs -- haven't tested disable_hw_scan=0 since the VOIP-friendly SW
> scanning patch, however).
>
> Do you want the log anyway? (modprobe iwl3945 debug=0x47ffffff
> disable_hw_scan=0 and runtime PCI powersave also enabled -- I don't
> know if it matters).
To test that patch powersave has to be explicitly enabled, since
it is disabled by default.
As this is not causing troubles with default disable_hw_scan option,
I'll post that patch.
You can provide me logs with disable_hw_scan=0, if you manage to
trigger a Microcode error.
Thanks
Stanislaw
> --
> Pedro
^ permalink raw reply
* Re: [BUG] 3.10 regression: hang on suspend
From: Arend van Spriel @ 2013-07-16 9:49 UTC (permalink / raw)
To: Ortwin Glück; +Cc: Stanislaw Gruszka, linux-kernel, linux-wireless
In-Reply-To: <51E4F790.6090308@odi.ch>
On 07/16/2013 09:34 AM, Ortwin Glück wrote:
>
>
> On 16.07.2013 08:56, Stanislaw Gruszka wrote:
>> Apparently this commit changed suspend procedure on mac80211, but it's
>> not obvious for me why it hangs :-(
>
> Hangs are hard :-) It just sits there with a black screen and a white
> cursor in the top left corner...
>
>> What is your user space configuration (are you using NM or other
>> software or maybe just wpa_supplicant)? Are you using wowlan?
>> If you do add no_console_suspend boot parameter does it print some
>> diagnostic messages during suspend before the hang ?
>
> Yes, I am using NM under KDE, with KDE triggered suspend. No wowlan
> AFAIK. The last thing I see in the log is something from NetworkManager
> that sees the device switching off. I can try again tonight and give you
> the exact message.
>
> I will also try without NM and bare wpa_supplicant and a plain suspend
> through sysfs.
>
> Any debug options you want me to enable? Netconsole won't work however...
Can you get more debug info if you try (as root/sudo -i):
echo devices > /sys/power/pm_test
echo mem > /sys/power state
Regards,
Arend
> Ortwin
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
^ permalink raw reply
* [PATCH] ath10k: fix NULL dereference for injected packets
From: Michal Kazior @ 2013-07-16 9:04 UTC (permalink / raw)
To: ath10k; +Cc: ymir.kr, linux-wireless, Michal Kazior
In-Reply-To: <CAMQ0DfRpqk6ufb4rAifjy651oM9-GZyDpMLL+mGVzzVSVjVyJA@mail.gmail.com>
Tx processing functions dereference vif and caused
NULL to be dereferenced for injected frames.
Don't call these functions at all for injected
frames. It doesn't make much sense to do so
anyway.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/mac.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 5082503..cdc08a0 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1687,10 +1687,14 @@ static void ath10k_tx(struct ieee80211_hw *hw,
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
}
- ath10k_tx_h_qos_workaround(hw, control, skb);
- ath10k_tx_h_update_wep_key(skb);
- ath10k_tx_h_add_p2p_noa_ie(ar, skb);
- ath10k_tx_h_seq_no(skb);
+ /* it makes no sense to process injected frames like that */
+ if (info->control.vif &&
+ info->control.vif->type != NL80211_IFTYPE_MONITOR) {
+ ath10k_tx_h_qos_workaround(hw, control, skb);
+ ath10k_tx_h_update_wep_key(skb);
+ ath10k_tx_h_add_p2p_noa_ie(ar, skb);
+ ath10k_tx_h_seq_no(skb);
+ }
memset(ATH10K_SKB_CB(skb), 0, sizeof(*ATH10K_SKB_CB(skb)));
ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 3/3] ath10k: create debugfs interface to trigger fw crash
From: Michal Kazior @ 2013-07-16 7:54 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1373961277-14784-1-git-send-email-michal.kazior@tieto.com>
This can be useful for testing. To perform a
forced firmware crash write 'crash' to
'simulate_fw_crash' debugfs file. E.g.
echo crash > /sys/kernel/debug/ieee80211/phy1/ath10k/simulate_fw_crash
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/debug.c | 54 +++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 65279f5..4021bea 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -445,6 +445,57 @@ static const struct file_operations fops_fw_stats = {
.llseek = default_llseek,
};
+static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char buf[] = "To simulate firmware crash write the keyword"
+ " `crash` to this file.\nThis will force firmware"
+ " to report a crash to the host system.\n";
+ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ char buf[32] = {};
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+ if (strcmp(buf, "crash") && strcmp(buf, "crash\n")) {
+ ath10k_warn("write keyword `crash` to simulate firmware crash\n");
+ goto exit;
+ }
+
+ if (ar->state != ATH10K_STATE_ON &&
+ ar->state != ATH10K_STATE_RESTARTED) {
+ ath10k_warn("firmware isn't loaded yet, nothing to crash\n");
+ goto exit;
+ }
+
+ ath10k_info("simulating firmware crash\n");
+
+ ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
+ if (ret)
+ ath10k_warn("failed to force fw hang (%d)\n", ret);
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return count;
+}
+
+static const struct file_operations fops_simulate_fw_crash = {
+ .read = ath10k_read_simulate_fw_crash,
+ .write = ath10k_write_simulate_fw_crash,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
@@ -461,6 +512,9 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_wmi_services);
+ debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
+ ar, &fops_simulate_fw_crash);
+
return 0;
}
#endif /* CONFIG_ATH10K_DEBUGFS */
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 2/3] ath10k: implement fw crash simulation command
From: Michal Kazior @ 2013-07-16 7:54 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1373961277-14784-1-git-send-email-michal.kazior@tieto.com>
This can be useful to test FW crash handling.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/wmi.c | 19 +++++++++++++++++++
drivers/net/wireless/ath/ath10k/wmi.h | 19 +++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 0d25cd7..5e42460 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2092,3 +2092,22 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
return ath10k_wmi_cmd_send(ar, skb, WMI_REQUEST_STATS_CMDID);
}
+
+int ath10k_wmi_force_fw_hang(struct ath10k *ar,
+ enum wmi_force_fw_hang_type type, u32 delay_ms)
+{
+ struct wmi_force_fw_hang_cmd *cmd;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_force_fw_hang_cmd *)skb->data;
+ cmd->type = __cpu_to_le32(type);
+ cmd->delay_ms = __cpu_to_le32(delay_ms);
+
+ ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
+ type, delay_ms);
+ return ath10k_wmi_cmd_send(ar, skb, WMI_FORCE_FW_HANG_CMDID);
+}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 9555f5a..da3b2bc 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -416,6 +416,7 @@ enum wmi_cmd_id {
WMI_PDEV_FTM_INTG_CMDID,
WMI_VDEV_SET_KEEPALIVE_CMDID,
WMI_VDEV_GET_KEEPALIVE_CMDID,
+ WMI_FORCE_FW_HANG_CMDID,
/* GPIO Configuration */
WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP(WMI_GRP_GPIO),
@@ -2972,6 +2973,22 @@ struct wmi_sta_keepalive_cmd {
struct wmi_sta_keepalive_arp_resp arp_resp;
} __packed;
+enum wmi_force_fw_hang_type {
+ WMI_FORCE_FW_HANG_ASSERT = 1,
+ WMI_FORCE_FW_HANG_NO_DETECT,
+ WMI_FORCE_FW_HANG_CTRL_EP_FULL,
+ WMI_FORCE_FW_HANG_EMPTY_POINT,
+ WMI_FORCE_FW_HANG_STACK_OVERFLOW,
+ WMI_FORCE_FW_HANG_INFINITE_LOOP,
+};
+
+#define WMI_FORCE_FW_HANG_RANDOM_TIME 0xFFFFFFFF
+
+struct wmi_force_fw_hang_cmd {
+ __le32 type;
+ __le32 delay_ms;
+} __packed;
+
#define ATH10K_RTS_MAX 2347
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
@@ -3048,5 +3065,7 @@ int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg);
int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
const struct wmi_pdev_set_wmm_params_arg *arg);
int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
+int ath10k_wmi_force_fw_hang(struct ath10k *ar,
+ enum wmi_force_fw_hang_type type, u32 delay_ms);
#endif /* _WMI_H_ */
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 1/3] ath10k: implement device recovery
From: Michal Kazior @ 2013-07-16 7:54 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1373961277-14784-1-git-send-email-michal.kazior@tieto.com>
Restart the hardware if FW crashes.
If FW crashes during recovery we leave the
hardware in a "wedged" state to avoid recursive
recoveries.
When in "wedged" state userspace may bring
interfaces down (to issue stop()) and then bring
one interface (to issue start()) to reload
hardware manually.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/core.c | 30 ++++++++++
drivers/net/wireless/ath/ath10k/core.h | 19 ++++++
drivers/net/wireless/ath/ath10k/htc.c | 3 +
drivers/net/wireless/ath/ath10k/mac.c | 101 ++++++++++++++++++++++++++------
drivers/net/wireless/ath/ath10k/mac.h | 1 +
drivers/net/wireless/ath/ath10k/pci.c | 2 +
drivers/net/wireless/ath/ath10k/wmi.c | 7 +++
7 files changed, 144 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index c37f79f..7226c23 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -476,6 +476,34 @@ static int ath10k_init_hw_params(struct ath10k *ar)
return 0;
}
+static void ath10k_core_restart(struct work_struct *work)
+{
+ struct ath10k *ar = container_of(work, struct ath10k, restart_work);
+
+ mutex_lock(&ar->conf_mutex);
+
+ switch (ar->state) {
+ case ATH10K_STATE_ON:
+ ath10k_halt(ar);
+ ar->state = ATH10K_STATE_RESTARTING;
+ ieee80211_restart_hw(ar->hw);
+ break;
+ case ATH10K_STATE_OFF:
+ /* this can happen if driver is being unloaded */
+ ath10k_warn("cannot restart a device that hasn't been started\n");
+ break;
+ case ATH10K_STATE_RESTARTING:
+ case ATH10K_STATE_RESTARTED:
+ ar->state = ATH10K_STATE_WEDGED;
+ /* fall through */
+ case ATH10K_STATE_WEDGED:
+ ath10k_warn("device is wedged, will not restart\n");
+ break;
+ }
+
+ mutex_unlock(&ar->conf_mutex);
+}
+
struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
const struct ath10k_hif_ops *hif_ops)
{
@@ -519,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
init_waitqueue_head(&ar->event_queue);
+ INIT_WORK(&ar->restart_work, ath10k_core_restart);
+
return ar;
err_wq:
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 413f1c5..9f21ecb 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -250,6 +250,23 @@ struct ath10k_debug {
enum ath10k_state {
ATH10K_STATE_OFF = 0,
ATH10K_STATE_ON,
+
+ /* When doing firmware recovery the device is first powered down.
+ * mac80211 is supposed to call in to start() hook later on. It is
+ * however possible that driver unloading and firmware crash overlap.
+ * mac80211 can wait on conf_mutex in stop() while the device is
+ * stopped in ath10k_core_restart() work holding conf_mutex. The state
+ * RESTARTED means that the device is up and mac80211 has started hw
+ * reconfiguration. Once mac80211 is done with the reconfiguration we
+ * set the state to STATE_ON in restart_complete(). */
+ ATH10K_STATE_RESTARTING,
+ ATH10K_STATE_RESTARTED,
+
+ /* The device has crashed while restarting hw. This state is like ON
+ * but commands are blocked in HTC and -ECOMM response is given. This
+ * prevents completion timeouts and makes the driver more responsive to
+ * userspace commands. This is also prevents recursive recovery. */
+ ATH10K_STATE_WEDGED,
};
struct ath10k {
@@ -355,6 +372,8 @@ struct ath10k {
enum ath10k_state state;
+ struct work_struct restart_work;
+
#ifdef CONFIG_ATH10K_DEBUGFS
struct ath10k_debug debug;
#endif
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 7d5a366..72e072c 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -246,6 +246,9 @@ int ath10k_htc_send(struct ath10k_htc *htc,
{
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
+ if (htc->ar->state == ATH10K_STATE_WEDGED)
+ return -ECOMM;
+
if (eid >= ATH10K_HTC_EP_COUNT) {
ath10k_warn("Invalid endpoint id: %d\n", eid);
return -ENOENT;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 2dfd446..b1bb318 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1738,7 +1738,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/*
* Initialize various parameters with default vaules.
*/
-static void ath10k_halt(struct ath10k *ar)
+void ath10k_halt(struct ath10k *ar)
{
lockdep_assert_held(&ar->conf_mutex);
@@ -1764,7 +1764,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
mutex_lock(&ar->conf_mutex);
- if (ar->state != ATH10K_STATE_OFF) {
+ if (ar->state != ATH10K_STATE_OFF &&
+ ar->state != ATH10K_STATE_RESTARTING) {
ret = -EINVAL;
goto exit;
}
@@ -1784,6 +1785,11 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto exit;
}
+ if (ar->state == ATH10K_STATE_OFF)
+ ar->state = ATH10K_STATE_ON;
+ else if (ar->state == ATH10K_STATE_RESTARTING)
+ ar->state = ATH10K_STATE_RESTARTED;
+
ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1);
if (ret)
ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
@@ -1806,22 +1812,47 @@ static void ath10k_stop(struct ieee80211_hw *hw)
struct ath10k *ar = hw->priv;
mutex_lock(&ar->conf_mutex);
- if (ar->state == ATH10K_STATE_ON)
+ if (ar->state == ATH10K_STATE_ON ||
+ ar->state == ATH10K_STATE_RESTARTED ||
+ ar->state == ATH10K_STATE_WEDGED)
ath10k_halt(ar);
ar->state = ATH10K_STATE_OFF;
mutex_unlock(&ar->conf_mutex);
cancel_work_sync(&ar->offchan_tx_work);
+ cancel_work_sync(&ar->restart_work);
}
-static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
+static void ath10k_config_ps(struct ath10k *ar)
{
struct ath10k_generic_iter ar_iter;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ /* During HW reconfiguration mac80211 reports all interfaces that were
+ * running until reconfiguration was started. Since FW doesn't have any
+ * vdevs at this point we must not iterate over this interface list.
+ * This setting will be updated upon add_interface(). */
+ if (ar->state == ATH10K_STATE_RESTARTED)
+ return;
+
+ memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
+ ar_iter.ar = ar;
+
+ ieee80211_iterate_active_interfaces_atomic(
+ ar->hw, IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_ps_iter, &ar_iter);
+
+ if (ar_iter.ret)
+ ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret);
+}
+
+static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
+{
struct ath10k *ar = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
int ret = 0;
- u32 flags;
mutex_lock(&ar->conf_mutex);
@@ -1833,18 +1864,8 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
spin_unlock_bh(&ar->data_lock);
}
- if (changed & IEEE80211_CONF_CHANGE_PS) {
- memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
- ar_iter.ar = ar;
- flags = IEEE80211_IFACE_ITER_RESUME_ALL;
-
- ieee80211_iterate_active_interfaces_atomic(hw,
- flags,
- ath10k_ps_iter,
- &ar_iter);
-
- ret = ar_iter.ret;
- }
+ if (changed & IEEE80211_CONF_CHANGE_PS)
+ ath10k_config_ps(ar);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (conf->flags & IEEE80211_CONF_MONITOR)
@@ -1853,6 +1874,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
ret = ath10k_monitor_destroy(ar);
}
+ ath10k_wmi_flush_tx(ar);
mutex_unlock(&ar->conf_mutex);
return ret;
}
@@ -2695,6 +2717,13 @@ static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
lockdep_assert_held(&arvif->ar->conf_mutex);
+ /* During HW reconfiguration mac80211 reports all interfaces that were
+ * running until reconfiguration was started. Since FW doesn't have any
+ * vdevs at this point we must not iterate over this interface list.
+ * This setting will be updated upon add_interface(). */
+ if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
+ return;
+
rts = min_t(u32, rts, ATH10K_RTS_MAX);
ar_iter->ret = ath10k_wmi_vdev_set_param(ar_iter->ar, arvif->vdev_id,
@@ -2735,6 +2764,13 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
lockdep_assert_held(&arvif->ar->conf_mutex);
+ /* During HW reconfiguration mac80211 reports all interfaces that were
+ * running until reconfiguration was started. Since FW doesn't have any
+ * vdevs at this point we must not iterate over this interface list.
+ * This setting will be updated upon add_interface(). */
+ if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
+ return;
+
frag = clamp_t(u32, frag,
ATH10K_FRAGMT_THRESHOLD_MIN,
ATH10K_FRAGMT_THRESHOLD_MAX);
@@ -2773,6 +2809,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct ath10k *ar = hw->priv;
+ bool skip;
int ret;
/* mac80211 doesn't care if we really xmit queued frames or not
@@ -2782,17 +2819,26 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
mutex_lock(&ar->conf_mutex);
+ if (ar->state == ATH10K_STATE_WEDGED)
+ goto skip;
+
ret = wait_event_timeout(ar->htt.empty_tx_wq, ({
bool empty;
+
spin_lock_bh(&ar->htt.tx_lock);
empty = bitmap_empty(ar->htt.used_msdu_ids,
ar->htt.max_num_pending_tx);
spin_unlock_bh(&ar->htt.tx_lock);
- (empty);
+
+ skip = (ar->state == ATH10K_STATE_WEDGED);
+
+ (empty || skip);
}), ATH10K_FLUSH_TIMEOUT_HZ);
- if (ret <= 0)
+
+ if (ret <= 0 || skip)
ath10k_warn("tx not flushed\n");
+skip:
mutex_unlock(&ar->conf_mutex);
}
@@ -2866,6 +2912,22 @@ static int ath10k_resume(struct ieee80211_hw *hw)
}
#endif
+static void ath10k_restart_complete(struct ieee80211_hw *hw)
+{
+ struct ath10k *ar = hw->priv;
+
+ mutex_lock(&ar->conf_mutex);
+
+ /* If device failed to restart it will be in a different state, e.g.
+ * ATH10K_STATE_WEDGED */
+ if (ar->state == ATH10K_STATE_RESTARTED) {
+ ath10k_info("device successfully recovered\n");
+ ar->state = ATH10K_STATE_ON;
+ }
+
+ mutex_unlock(&ar->conf_mutex);
+}
+
static const struct ieee80211_ops ath10k_ops = {
.tx = ath10k_tx,
.start = ath10k_start,
@@ -2886,6 +2948,7 @@ static const struct ieee80211_ops ath10k_ops = {
.set_frag_threshold = ath10k_set_frag_threshold,
.flush = ath10k_flush,
.tx_last_beacon = ath10k_tx_last_beacon,
+ .restart_complete = ath10k_restart_complete,
#ifdef CONFIG_PM
.suspend = ath10k_suspend,
.resume = ath10k_resume,
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index 27fc92e..6fce9bf 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -34,6 +34,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
void ath10k_reset_scan(unsigned long ptr);
void ath10k_offchan_tx_purge(struct ath10k *ar);
void ath10k_offchan_tx_work(struct work_struct *work);
+void ath10k_halt(struct ath10k *ar);
static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
{
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index bfe8561..c71b488 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -720,6 +720,8 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
reg_dump_values[i + 1],
reg_dump_values[i + 2],
reg_dump_values[i + 3]);
+
+ ieee80211_queue_work(ar->hw, &ar->restart_work);
}
static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index b7e7e45..0d25cd7 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -27,6 +27,13 @@ void ath10k_wmi_flush_tx(struct ath10k *ar)
{
int ret;
+ lockdep_assert_held(&ar->conf_mutex);
+
+ if (ar->state == ATH10K_STATE_WEDGED) {
+ ath10k_warn("wmi flush skipped - device is wedged anyway\n");
+ return;
+ }
+
ret = wait_event_timeout(ar->wmi.wq,
atomic_read(&ar->wmi.pending_tx_count) == 0,
5*HZ);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 0/3] ath10k: hardware recovery
From: Michal Kazior @ 2013-07-16 7:54 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1372148011-28234-1-git-send-email-michal.kazior@tieto.com>
Respin of hw recovery. This implements recovery
from a firmware crash.
Note: this is based on my
"ath10k: device setup refactor" patchset.
v3:
* rename RESTARTING_ON/OFF to RESTARTING/RESTARTED
* update commit message for 'create debufs..'
Michal Kazior (3):
ath10k: implement device recovery
ath10k: implement fw crash simulation command
ath10k: create debugfs interface to trigger fw crash
drivers/net/wireless/ath/ath10k/core.c | 30 +++++++++
drivers/net/wireless/ath/ath10k/core.h | 19 ++++++
drivers/net/wireless/ath/ath10k/debug.c | 54 +++++++++++++++++
drivers/net/wireless/ath/ath10k/htc.c | 3 +
drivers/net/wireless/ath/ath10k/mac.c | 101 +++++++++++++++++++++++++------
drivers/net/wireless/ath/ath10k/mac.h | 1 +
drivers/net/wireless/ath/ath10k/pci.c | 2 +
drivers/net/wireless/ath/ath10k/wmi.c | 26 ++++++++
drivers/net/wireless/ath/ath10k/wmi.h | 19 ++++++
9 files changed, 236 insertions(+), 19 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH v4 10/10] ath10k: skip fw stats debugfs interface if device is down
From: Michal Kazior @ 2013-07-16 7:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1373960339-8525-1-git-send-email-michal.kazior@tieto.com>
If the device is not running then there may be no
FW at all to send the query to. If the FW is
already there it might still trigger a crash if
the command is sent before the device is fully
initialized.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/debug.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 499034b..65279f5 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -161,7 +161,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
struct wmi_pdev_stats *ps;
int i;
- mutex_lock(&ar->conf_mutex);
+ spin_lock_bh(&ar->data_lock);
stats = &ar->debug.target_stats;
@@ -259,6 +259,7 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
}
}
+ spin_unlock_bh(&ar->data_lock);
mutex_unlock(&ar->conf_mutex);
complete(&ar->debug.event_stats_compl);
}
@@ -268,35 +269,35 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
{
struct ath10k *ar = file->private_data;
struct ath10k_target_stats *fw_stats;
- char *buf;
+ char *buf = NULL;
unsigned int len = 0, buf_len = 2500;
- ssize_t ret_cnt;
+ ssize_t ret_cnt = 0;
long left;
int i;
int ret;
fw_stats = &ar->debug.target_stats;
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH10K_STATE_ON)
+ goto exit;
+
buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf)
- return -ENOMEM;
+ goto exit;
ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
if (ret) {
ath10k_warn("could not request stats (%d)\n", ret);
- kfree(buf);
- return -EIO;
+ goto exit;
}
left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
+ if (left <= 0)
+ goto exit;
- if (left <= 0) {
- kfree(buf);
- return -ETIMEDOUT;
- }
-
- mutex_lock(&ar->conf_mutex);
-
+ spin_lock_bh(&ar->data_lock);
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s\n",
"ath10k PDEV stats");
@@ -424,14 +425,15 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
fw_stats->peer_stat[i].peer_tx_rate);
len += scnprintf(buf + len, buf_len - len, "\n");
}
+ spin_unlock_bh(&ar->data_lock);
if (len > buf_len)
len = buf_len;
ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+exit:
mutex_unlock(&ar->conf_mutex);
-
kfree(buf);
return ret_cnt;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v4 09/10] ath10k: store firmware files in memory
From: Michal Kazior @ 2013-07-16 7:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1373960339-8525-1-git-send-email-michal.kazior@tieto.com>
Different FW versions may provide different
functions thus mean different hw capabilities
advertised to mac80211.
It is safe to swap firmware files on disk during
driver/device runtime without worries.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/core.c | 157 +++++++++++++++++++++-----------
drivers/net/wireless/ath/ath10k/core.h | 4 +
2 files changed, 109 insertions(+), 52 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 1d4c245..c37f79f 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -247,19 +247,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,
static int ath10k_download_board_data(struct ath10k *ar)
{
+ const struct firmware *fw = ar->board_data;
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 address;
- const struct firmware *fw;
int ret;
- fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
- ar->hw_params.fw.board);
- if (IS_ERR(fw)) {
- ath10k_err("could not fetch board data fw file (%ld)\n",
- PTR_ERR(fw));
- return PTR_ERR(fw);
- }
-
ret = ath10k_push_board_ext_data(ar, fw);
if (ret) {
ath10k_err("could not push board ext data (%d)\n", ret);
@@ -286,32 +278,20 @@ static int ath10k_download_board_data(struct ath10k *ar)
}
exit:
- release_firmware(fw);
return ret;
}
static int ath10k_download_and_run_otp(struct ath10k *ar)
{
- const struct firmware *fw;
- u32 address;
+ const struct firmware *fw = ar->otp;
+ u32 address = ar->hw_params.patch_load_addr;
u32 exec_param;
int ret;
/* OTP is optional */
- if (ar->hw_params.fw.otp == NULL) {
- ath10k_info("otp file not defined\n");
- return 0;
- }
-
- address = ar->hw_params.patch_load_addr;
-
- fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
- ar->hw_params.fw.otp);
- if (IS_ERR(fw)) {
- ath10k_warn("could not fetch otp (%ld)\n", PTR_ERR(fw));
+ if (!ar->otp)
return 0;
- }
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
if (ret) {
@@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
}
exit:
- release_firmware(fw);
return ret;
}
static int ath10k_download_fw(struct ath10k *ar)
{
- const struct firmware *fw;
+ const struct firmware *fw = ar->firmware;
u32 address;
int ret;
- if (ar->hw_params.fw.fw == NULL)
- return -EINVAL;
-
address = ar->hw_params.patch_load_addr;
- fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
- ar->hw_params.fw.fw);
- if (IS_ERR(fw)) {
- ath10k_err("could not fetch fw (%ld)\n", PTR_ERR(fw));
- return PTR_ERR(fw);
- }
-
ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
if (ret) {
ath10k_err("could not write fw (%d)\n", ret);
@@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar)
}
exit:
- release_firmware(fw);
+ return ret;
+}
+
+static void ath10k_core_free_firmware_files(struct ath10k *ar)
+{
+ if (ar->board_data && !IS_ERR(ar->board_data))
+ release_firmware(ar->board_data);
+
+ if (ar->otp && !IS_ERR(ar->otp))
+ release_firmware(ar->otp);
+
+ if (ar->firmware && !IS_ERR(ar->firmware))
+ release_firmware(ar->firmware);
+
+ ar->board_data = NULL;
+ ar->otp = NULL;
+ ar->firmware = NULL;
+}
+
+static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
+{
+ int ret = 0;
+
+ if (ar->hw_params.fw.fw == NULL) {
+ ath10k_err("firmware file not defined\n");
+ return -EINVAL;
+ }
+
+ if (ar->hw_params.fw.board == NULL) {
+ ath10k_err("board data file not defined");
+ return -EINVAL;
+ }
+
+ ar->board_data = ath10k_fetch_fw_file(ar,
+ ar->hw_params.fw.dir,
+ ar->hw_params.fw.board);
+ if (IS_ERR(ar->board_data)) {
+ ret = PTR_ERR(ar->board_data);
+ ath10k_err("could not fetch board data (%d)\n", ret);
+ goto err;
+ }
+
+ ar->firmware = ath10k_fetch_fw_file(ar,
+ ar->hw_params.fw.dir,
+ ar->hw_params.fw.fw);
+ if (IS_ERR(ar->firmware)) {
+ ret = PTR_ERR(ar->firmware);
+ ath10k_err("could not fetch firmware (%d)\n", ret);
+ goto err;
+ }
+
+ /* OTP may be undefined. If so, don't fetch it at all */
+ if (ar->hw_params.fw.otp == NULL)
+ return 0;
+
+ ar->otp = ath10k_fetch_fw_file(ar,
+ ar->hw_params.fw.dir,
+ ar->hw_params.fw.otp);
+ if (IS_ERR(ar->otp)) {
+ ret = PTR_ERR(ar->otp);
+ ath10k_err("could not fetch otp (%d)\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ ath10k_core_free_firmware_files(ar);
return ret;
}
@@ -502,23 +538,10 @@ EXPORT_SYMBOL(ath10k_core_destroy);
int ath10k_core_start(struct ath10k *ar)
{
- struct bmi_target_info target_info;
int status;
ath10k_bmi_start(ar);
- memset(&target_info, 0, sizeof(target_info));
- status = ath10k_bmi_get_target_info(ar, &target_info);
- if (status)
- goto err;
-
- ar->target_version = target_info.version;
- ar->hw->wiphy->hw_version = target_info.version;
-
- status = ath10k_init_hw_params(ar);
- if (status)
- goto err;
-
if (ath10k_init_configure_target(ar)) {
status = -EINVAL;
goto err;
@@ -617,7 +640,8 @@ EXPORT_SYMBOL(ath10k_core_stop);
* hook will try to init it again) before registering */
static int ath10k_core_probe_fw(struct ath10k *ar)
{
- int ret;
+ struct bmi_target_info target_info;
+ int ret = 0;
ret = ath10k_hif_power_up(ar);
if (ret) {
@@ -625,9 +649,35 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
return ret;
}
+ memset(&target_info, 0, sizeof(target_info));
+ ret = ath10k_bmi_get_target_info(ar, &target_info);
+ if (ret) {
+ ath10k_err("could not get target info (%d)\n", ret);
+ ath10k_hif_power_down(ar);
+ return ret;
+ }
+
+ ar->target_version = target_info.version;
+ ar->hw->wiphy->hw_version = target_info.version;
+
+ ret = ath10k_init_hw_params(ar);
+ if (ret) {
+ ath10k_err("could not get hw params (%d)\n", ret);
+ ath10k_hif_power_down(ar);
+ return ret;
+ }
+
+ ret = ath10k_core_fetch_firmware_files(ar);
+ if (ret) {
+ ath10k_err("could not fetch firmware files (%d)\n", ret);
+ ath10k_hif_power_down(ar);
+ return ret;
+ }
+
ret = ath10k_core_start(ar);
if (ret) {
ath10k_err("could not init core (%d)\n", ret);
+ ath10k_core_free_firmware_files(ar);
ath10k_hif_power_down(ar);
return ret;
}
@@ -650,7 +700,7 @@ int ath10k_core_register(struct ath10k *ar)
status = ath10k_mac_register(ar);
if (status) {
ath10k_err("could not register to mac80211 (%d)\n", status);
- return status;
+ goto err_release_fw;
}
status = ath10k_debug_create(ar);
@@ -663,6 +713,8 @@ int ath10k_core_register(struct ath10k *ar)
err_unregister_mac:
ath10k_mac_unregister(ar);
+err_release_fw:
+ ath10k_core_free_firmware_files(ar);
return status;
}
EXPORT_SYMBOL(ath10k_core_register);
@@ -673,6 +725,7 @@ void ath10k_core_unregister(struct ath10k *ar)
* Otherwise we will fail to submit commands to FW and mac80211 will be
* unhappy about callback failures. */
ath10k_mac_unregister(ar);
+ ath10k_core_free_firmware_files(ar);
}
EXPORT_SYMBOL(ath10k_core_unregister);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 5c94ea0..413f1c5 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -300,6 +300,10 @@ struct ath10k {
} fw;
} hw_params;
+ const struct firmware *board_data;
+ const struct firmware *otp;
+ const struct firmware *firmware;
+
struct {
struct completion started;
struct completion completed;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v4 08/10] ath10k: defer hw setup to start/stop mac80211 hooks
From: Michal Kazior @ 2013-07-16 7:38 UTC (permalink / raw)
To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1373960339-8525-1-git-send-email-michal.kazior@tieto.com>
This fixes suspend-to-disk. The hardware is now
re-initialized upon freeze/thaw properly.
This also makes suspend/resume re-initialize the
hardware as WoWLAN support is not done yet.
With some little work it should be possible to
support hw reconfiguration for hw/fw recovery.
HW must be initialized once before registering to
mac80211 because FW determinates what hw
capabilities can be advertised.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/core.c | 46 +++++++++++++++++++++-----
drivers/net/wireless/ath/ath10k/mac.c | 56 ++++++++++++++++++++++++--------
drivers/net/wireless/ath/ath10k/pci.c | 11 +------
3 files changed, 81 insertions(+), 32 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 0e4a704..1d4c245 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -601,6 +601,7 @@ err_wmi_detach:
err:
return status;
}
+EXPORT_SYMBOL(ath10k_core_start);
void ath10k_core_stop(struct ath10k *ar)
{
@@ -608,18 +609,49 @@ void ath10k_core_stop(struct ath10k *ar)
ath10k_htt_detach(&ar->htt);
ath10k_wmi_detach(ar);
}
+EXPORT_SYMBOL(ath10k_core_stop);
+
+/* mac80211 manages fw/hw initialization through start/stop hooks. However in
+ * order to know what hw capabilities should be advertised to mac80211 it is
+ * necessary to load the firmware (and tear it down immediately since start
+ * hook will try to init it again) before registering */
+static int ath10k_core_probe_fw(struct ath10k *ar)
+{
+ int ret;
+
+ ret = ath10k_hif_power_up(ar);
+ if (ret) {
+ ath10k_err("could not start pci hif (%d)\n", ret);
+ return ret;
+ }
+
+ ret = ath10k_core_start(ar);
+ if (ret) {
+ ath10k_err("could not init core (%d)\n", ret);
+ ath10k_hif_power_down(ar);
+ return ret;
+ }
+
+ ath10k_core_stop(ar);
+ ath10k_hif_power_down(ar);
+ return 0;
+}
int ath10k_core_register(struct ath10k *ar)
{
int status;
- status = ath10k_core_start(ar);
- if (status)
- goto err;
+ status = ath10k_core_probe_fw(ar);
+ if (status) {
+ ath10k_err("could not probe fw (%d)\n", status);
+ return status;
+ }
status = ath10k_mac_register(ar);
- if (status)
- goto err_core_stop;
+ if (status) {
+ ath10k_err("could not register to mac80211 (%d)\n", status);
+ return status;
+ }
status = ath10k_debug_create(ar);
if (status) {
@@ -631,9 +663,6 @@ int ath10k_core_register(struct ath10k *ar)
err_unregister_mac:
ath10k_mac_unregister(ar);
-err_core_stop:
- ath10k_core_stop(ar);
-err:
return status;
}
EXPORT_SYMBOL(ath10k_core_register);
@@ -644,7 +673,6 @@ void ath10k_core_unregister(struct ath10k *ar)
* Otherwise we will fail to submit commands to FW and mac80211 will be
* unhappy about callback failures. */
ath10k_mac_unregister(ar);
- ath10k_core_stop(ar);
}
EXPORT_SYMBOL(ath10k_core_unregister);
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index b9663e9..2dfd446 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1738,13 +1738,52 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/*
* Initialize various parameters with default vaules.
*/
+static void ath10k_halt(struct ath10k *ar)
+{
+ lockdep_assert_held(&ar->conf_mutex);
+
+ del_timer_sync(&ar->scan.timeout);
+ ath10k_offchan_tx_purge(ar);
+ ath10k_peer_cleanup_all(ar);
+ ath10k_core_stop(ar);
+ ath10k_hif_power_down(ar);
+
+ spin_lock_bh(&ar->data_lock);
+ if (ar->scan.in_progress) {
+ del_timer(&ar->scan.timeout);
+ ar->scan.in_progress = false;
+ ieee80211_scan_completed(ar->hw, true);
+ }
+ spin_unlock_bh(&ar->data_lock);
+}
+
static int ath10k_start(struct ieee80211_hw *hw)
{
struct ath10k *ar = hw->priv;
- int ret;
+ int ret = 0;
mutex_lock(&ar->conf_mutex);
+ if (ar->state != ATH10K_STATE_OFF) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = ath10k_hif_power_up(ar);
+ if (ret) {
+ ath10k_err("could not init hif (%d)\n", ret);
+ ar->state = ATH10K_STATE_OFF;
+ goto exit;
+ }
+
+ ret = ath10k_core_start(ar);
+ if (ret) {
+ ath10k_err("could not init core (%d)\n", ret);
+ ath10k_hif_power_down(ar);
+ ar->state = ATH10K_STATE_OFF;
+ goto exit;
+ }
+
ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1);
if (ret)
ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
@@ -1755,9 +1794,9 @@ static int ath10k_start(struct ieee80211_hw *hw)
ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
ret);
- ar->state = ATH10K_STATE_ON;
ath10k_regd_update(ar);
+exit:
mutex_unlock(&ar->conf_mutex);
return 0;
}
@@ -1767,17 +1806,8 @@ static void ath10k_stop(struct ieee80211_hw *hw)
struct ath10k *ar = hw->priv;
mutex_lock(&ar->conf_mutex);
- del_timer_sync(&ar->scan.timeout);
- ath10k_offchan_tx_purge(ar);
- ath10k_peer_cleanup_all(ar);
-
- spin_lock_bh(&ar->data_lock);
- if (ar->scan.in_progress) {
- del_timer(&ar->scan.timeout);
- ar->scan.in_progress = false;
- ieee80211_scan_completed(ar->hw, true);
- }
- spin_unlock_bh(&ar->data_lock);
+ if (ar->state == ATH10K_STATE_ON)
+ ath10k_halt(ar);
ar->state = ATH10K_STATE_OFF;
mutex_unlock(&ar->conf_mutex);
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 75f5427..bfe8561 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2362,22 +2362,14 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_iomap;
}
- ret = ath10k_pci_hif_power_up(ar);
- if (ret) {
- ath10k_err("could not start pci hif (%d)\n", ret);
- goto err_intr;
- }
-
ret = ath10k_core_register(ar);
if (ret) {
ath10k_err("could not register driver core (%d)\n", ret);
- goto err_hif;
+ goto err_intr;
}
return 0;
-err_hif:
- ath10k_pci_hif_power_down(ar);
err_intr:
ath10k_pci_stop_intr(ar);
err_iomap:
@@ -2416,7 +2408,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
tasklet_kill(&ar_pci->msi_fw_err);
ath10k_core_unregister(ar);
- ath10k_pci_hif_power_down(ar);
ath10k_pci_stop_intr(ar);
pci_set_drvdata(pdev, NULL);
--
1.7.9.5
^ 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