* [PATCH] rtlwifi: rtl8192ee: New firmware from Realtek
From: Larry Finger @ 2016-12-17 18:50 UTC (permalink / raw)
To: linux-firmware; +Cc: linux-wireless, Troy Tan, netdev, Larry Finger
From: Troy Tan <troy_tan@realsil.com.cn>
Recent testing by Realtek found bugs in both the driver and firmware for
the RTL8192EE chips.
Signed-off-by: Troy Tan <troy_tan@realsil.com.cn>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
WHENCE | 5 ++++-
rtlwifi/rtl8192eefw.bin | Bin 32754 -> 31818 bytes
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/WHENCE b/WHENCE
index df2dffa..c6f650e 100644
--- a/WHENCE
+++ b/WHENCE
@@ -2115,7 +2115,10 @@ Licence: Redistributable. See LICENCE.rtlwifi_firmware.txt for details.
Driver: rtl8192ee - Realtek 802.11n WLAN driver for RTL8192EE
-Info: Taken from Realtek version rtl_92ce_92se_92de_8723ae_88ee_8723be_92ee_linux_mac80211_0017.1224.2013
+Info: Initial version taken from Realtek version
+ rtl_92ce_92se_92de_8723ae_88ee_8723be_92ee_linux_mac80211_0017.1224.2013
+ Updated Jan. 14, 2015 with file added by Realtek to
+ http://github.com/lwfinger/rtlwifi_new.git.
File: rtlwifi/rtl8192eefw.bin
Licence: Redistributable. See LICENCE.rtlwifi_firmware.txt for details.
diff --git a/rtlwifi/rtl8192eefw.bin b/rtlwifi/rtl8192eefw.bin
index bede1ad79f9c5243484f31c790ef794d579c9b4b..4a034d3ae8910df49682876dfe44fe8690798825 100644
GIT binary patch
literal 31818
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
KP@SgNTmK&fTs;*4
literal 32754
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
QSXYengSk?jru9Sq59%k7NdN!<
--
2.1.2
^ permalink raw reply related
* [PATCH] ath10k: merge extended peer info data with existing peers info
From: Christian Lamparter @ 2016-12-17 17:46 UTC (permalink / raw)
To: linux-wireless, ath10k; +Cc: Mohammed Shafi Shajakhan, Kalle Valo
In-Reply-To: <20161216052418.GA8936@atheros-ThinkPad-T61>
The 10.4 firmware adds extended peer information to the
firmware's statistics payload. This additional info is
stored as a separate data field. During review of
"ath10k: add accounting for the extended peer statistics" [0]
Mohammed Shafi Shajakhan commented that the extended peer statistics
lists are of little use:"... there is not much use in appending
the extended peer stats (which gets periodically updated) to the
linked list '&ar->debug.fw_stats.peers_extd)' and should we get
rid of the below (and the required cleanup as well)
list_splice_tail_init(&stats.peers_extd,
&ar->debug.fw_stats.peers_extd);
since rx_duration is getting updated periodically to the per sta
information."
This patch replaces the extended peers list with a lookup and
puts the retrieved data (rx_duration) into the existing
ath10k_fw_stats_peer entry that was created earlier.
[0] <https://lkml.kernel.org/r/992a4e2676037a06f482cdbe2d3d39e287530be5.1480974623.git.chunkeey@googlemail.com>
Cc: Mohammed Shafi Shajakhan <mohammed@codeaurora.org>
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
---
drivers/net/wireless/ath/ath10k/core.h | 2 --
drivers/net/wireless/ath/ath10k/debug.c | 17 --------------
drivers/net/wireless/ath/ath10k/debugfs_sta.c | 32 ++-----------------------
drivers/net/wireless/ath/ath10k/wmi.c | 34 ++++++++++++++++++++-------
4 files changed, 28 insertions(+), 57 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 09ff8b8a6441..3fffbbb18c25 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -268,11 +268,9 @@ struct ath10k_fw_stats_pdev {
};
struct ath10k_fw_stats {
- bool extended;
struct list_head pdevs;
struct list_head vdevs;
struct list_head peers;
- struct list_head peers_extd;
};
#define ATH10K_TPC_TABLE_TYPE_FLAG 1
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 82a4c67f3672..89f7fde77cdf 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -315,25 +315,13 @@ static void ath10k_fw_stats_peers_free(struct list_head *head)
}
}
-static void ath10k_fw_extd_stats_peers_free(struct list_head *head)
-{
- struct ath10k_fw_extd_stats_peer *i, *tmp;
-
- list_for_each_entry_safe(i, tmp, head, list) {
- list_del(&i->list);
- kfree(i);
- }
-}
-
static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
{
spin_lock_bh(&ar->data_lock);
ar->debug.fw_stats_done = false;
- ar->debug.fw_stats.extended = false;
ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
- ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
spin_unlock_bh(&ar->data_lock);
}
@@ -348,7 +336,6 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
INIT_LIST_HEAD(&stats.pdevs);
INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.peers);
- INIT_LIST_HEAD(&stats.peers_extd);
spin_lock_bh(&ar->data_lock);
ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
@@ -411,8 +398,6 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
- list_splice_tail_init(&stats.peers_extd,
- &ar->debug.fw_stats.peers_extd);
}
complete(&ar->debug.fw_stats_complete);
@@ -424,7 +409,6 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
ath10k_fw_stats_pdevs_free(&stats.pdevs);
ath10k_fw_stats_vdevs_free(&stats.vdevs);
ath10k_fw_stats_peers_free(&stats.peers);
- ath10k_fw_extd_stats_peers_free(&stats.peers_extd);
spin_unlock_bh(&ar->data_lock);
}
@@ -2347,7 +2331,6 @@ int ath10k_debug_create(struct ath10k *ar)
INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
- INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index fce6f8137d33..bf2d49cbb3bb 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -18,27 +18,8 @@
#include "wmi-ops.h"
#include "debug.h"
-static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
- struct ath10k_fw_stats *stats)
-{
- struct ath10k_fw_extd_stats_peer *peer;
- struct ieee80211_sta *sta;
- struct ath10k_sta *arsta;
-
- rcu_read_lock();
- list_for_each_entry(peer, &stats->peers_extd, list) {
- sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
- NULL);
- if (!sta)
- continue;
- arsta = (struct ath10k_sta *)sta->drv_priv;
- arsta->rx_duration += (u64)peer->rx_duration;
- }
- rcu_read_unlock();
-}
-
-static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
- struct ath10k_fw_stats *stats)
+void ath10k_sta_update_rx_duration(struct ath10k *ar,
+ struct ath10k_fw_stats *stats)
{
struct ath10k_fw_stats_peer *peer;
struct ieee80211_sta *sta;
@@ -56,15 +37,6 @@ static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
rcu_read_unlock();
}
-void ath10k_sta_update_rx_duration(struct ath10k *ar,
- struct ath10k_fw_stats *stats)
-{
- if (stats->extended)
- ath10k_sta_update_extd_stats_rx_duration(ar, stats);
- else
- ath10k_sta_update_stats_rx_duration(ar, stats);
-}
-
void ath10k_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct station_info *sinfo)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c893314a191f..c7ec7b9e9b55 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -3044,23 +3044,41 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar,
if ((stats_id & WMI_10_4_STAT_PEER_EXTD) == 0)
return 0;
- stats->extended = true;
-
for (i = 0; i < num_peer_stats; i++) {
const struct wmi_10_4_peer_extd_stats *src;
- struct ath10k_fw_extd_stats_peer *dst;
+ struct ath10k_fw_stats_peer *dst;
src = (void *)skb->data;
if (!skb_pull(skb, sizeof(*src)))
return -EPROTO;
- dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- if (!dst)
- continue;
+ /* Because the stat data may exceed htc-wmi buffer
+ * limit the firmware might split the stats data
+ * and delivers it in multiple update events.
+ * if we can't find the entry in the current event
+ * payload, we have to look in main list as well.
+ */
+ list_for_each_entry(dst, &stats->peers, list) {
+ if (ether_addr_equal(dst->peer_macaddr,
+ src->peer_macaddr.addr))
+ goto found;
+ }
+
+#ifdef CONFIG_ATH10K_DEBUGFS
+ list_for_each_entry(dst, &ar->debug.fw_stats.peers, list) {
+ if (ether_addr_equal(dst->peer_macaddr,
+ src->peer_macaddr.addr))
+ goto found;
+ }
+#endif
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "Orphaned extended stats entry for station %pM.\n",
+ src->peer_macaddr.addr);
+ continue;
- ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
+found:
dst->rx_duration = __le32_to_cpu(src->rx_duration);
- list_add_tail(&dst->list, &stats->peers_extd);
}
return 0;
--
2.11.0
^ permalink raw reply related
* Re: [PATCH v2 0/7] ath9k: EEPROM swapping improvements
From: Martin Blumenstingl @ 2016-12-17 14:40 UTC (permalink / raw)
To: Adrian Chadd
Cc: Valo, Kalle, ath9k-devel, linux-wireless@vger.kernel.org,
ath9k-devel@lists.ath9k.org, devicetree@vger.kernel.org,
arnd@arndb.de, chunkeey@googlemail.com, nbd@nbd.name
In-Reply-To: <CAJ-Vmo=3zox7QkFUA-3yxtvSTzPT4GiFkoOUU3cPTXSN4xV8vQ@mail.gmail.com>
Hi Adrian,
On Wed, Dec 14, 2016 at 7:45 AM, Adrian Chadd <adrian@freebsd.org> wrote:
> hi,
>
> On 12 December 2016 at 12:05, Martin Blumenstingl
> <martin.blumenstingl@googlemail.com> wrote:
>
>>
>> It seems that there are a few devices out there where the whole EEPROM
>> is swab16'ed which switches the position of the 1-byte fields
>> opCapFlags and eepMisc.
>> those still work fine with the new code, however I had a second patch
>> in LEDE [0] which results in ath9k_platform_data.endian_check NOT
>> being set anymore.
>> that endian_check flag was used before to swab16 the whole EEPROM, to
>> correct the position of the 1-byte fields again.
>> Currently we are fixing this in the firmware hotplug script: [1]
>> This is definitely not a blocker for this series though (if we want to
>> have a devicetree replacement for "ath9k_platform_data.endian_check"
>> then I'd work on that within a separate series, but I somewhat
>> consider these EEPROMs as "broken" so fixing them in
>> userspace/firmware hotplug script is fine for me)
>
> As a reference - the reference driver has been doign this for a while.
> It attempts to detect the endianness by looking at the 0xa55a
> signature endian and figuring out which endian the actual contents are
> in.
>
> So just FYI yeah, this is a "thing" for reasons I don't quite know.
on all devices I have seen so far (all customer devices, no
development boards) these two magic bytes *can* be used to detect the
endianness of the data that is written to the PCI memory (and thus
whether swapping of that data is required or not).
however, there are many devices (roughly 50% of the ones I've seen)
where the magic bytes cannot be used to swap the actual EEPROM (=
calibration) data because they are "inverted". reading the eepMisc
byte works fine on all devices I've seen so far *if* the manufacturer
did not swab16 all data (PCI memory and EEPROM data).
on the other hand you are right: all four devices which were broken
had the correct magic bytes at the start, but as long as this is not
the case for all devices we cannot use it without some feature-flag.
as an (unrelated) side-note: I've also some EEPROMs where the length
matches neither the "magic bytes endianness" nor the "eepMisc
endianness". I consider these broken as well, but fortunately ath9k
has a fallback for this issue.
Regards,
Martin
^ permalink raw reply
* MAC address in wl1251 NVS data (Was: Re: wl1251 NVS calibration data format)
From: Pali Rohár @ 2016-12-17 13:10 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Gery Kahn, Shahar Lev, Kalle Valo, linux-wireless, linux-kernel,
Pavel Machek, Ivaylo Dimitrov
In-Reply-To: <20161217120350.phnlfhklwfqqgbjr@earth>
[-- Attachment #1: Type: Text/Plain, Size: 2381 bytes --]
> On Sat, Dec 17, 2016 at 12:14:50PM +0100, Pali Rohár wrote:
> > > [1] http://notaz.gp2x.de/misc/pnd/wl1251/nvs_map.txt
> > In that description is something about STA mac address:
> >
019 02 //length
> > 01a 6d //STA_ADDR_L Register Address. (STA MAC
> > Address)
> > 01b 54 //
> > 01c 00 //STA_ADDR_L Register
> > 01d 00 //
> > 01e 32 //
> > 01f 28 //
> > 020 00 //STA_ADDR_H Register Data.
021 08 //
022 00 //
023 00 //
So... above data means:
019 - number of words
01a - low bits of offset applied with mask 0xfe
01b - high bits of offset
01c-01f first word
020-023 second word
Interpreted as: at address offset 0x536c are written two words
0x28320000 and 0x00000800
wl1271 driver has in linux/drivers/net/wireless/ti/wlcore/boot.c this:
/* update current MAC address to NVS */
nvs_ptr[11] = wl->addresses[0].addr[0];
nvs_ptr[10] = wl->addresses[0].addr[1];
nvs_ptr[6] = wl->addresses[0].addr[2];
nvs_ptr[5] = wl->addresses[0].addr[3];
nvs_ptr[4] = wl->addresses[0].addr[4];
nvs_ptr[3] = wl->addresses[0].addr[5];
Looking at wl1271-nvs.bin file (which is "modified" in kernel by boot.c)
000: 01
001: 6d
002: 54
003: 00
004: 00
005: ef
006: be
Means: at address offset 0x536c is written one word 0xBEEF0000
007: 01
008: 71
009: 54
00a: ad
00b: de
00c: 00
00d: 00
Means: at address offset 0x5371 is written one word 0x0000DEAD
Above boot.c kernel code updates those data to MAC address, so at
address offset 0x536c is written four low bytes of MAC address and to
0x5371 are written remaining two bytes. So 00:00:DE:AD:BE:EF
So conclusion: address offset for wl1271 (where is written MAC address)
is exactly same as for wl1251 which is marked in that documentation as
STA_ADDR_L Register.
Btw, in our wl1251-nvs.bin found in Maemo rootfs, which is exactly same
as in linux-firmware.git tree there are those data:
019: 02
01a: 6d
01b: 54
01c: 09
01d: 03
01e: 07
01f: 20
020: 00
021: 00
022: 00
023: 00
So hardcoded MAC address in wl1251-nvs.bin is: 00:00:20:07:03:09. Which
is assigned to DIAB. Strange that it is not TI...
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: wl1251 NVS calibration data format
From: Sebastian Reichel @ 2016-12-17 12:03 UTC (permalink / raw)
To: Pali Rohár
Cc: Gery Kahn, Shahar Lev, Kalle Valo, linux-wireless, linux-kernel,
Pavel Machek, Ivaylo Dimitrov
In-Reply-To: <201612171214.50820@pali>
[-- Attachment #1: Type: text/plain, Size: 2595 bytes --]
Hi,
On Sat, Dec 17, 2016 at 12:14:50PM +0100, Pali Rohár wrote:
> On Saturday 17 December 2016 10:37:05 Sebastian Reichel wrote:
> > On Fri, Dec 16, 2016 at 12:01:48PM +0100, Pali Rohár wrote:
> > > Hi! Do you know format of wl1251 NVS calibration data file?
> > >
> > > I found that there is tool for changing NVS file for wl1271 and
> > > newer chips (so not for wl1251!) at:
> > > https://github.com/gxk/ti-utils
> > >
> > > And wl1271 has in NVS data already place for MAC address. And in
> > > wlcore (for wl1271 and newer) there is really kernel code which is
> > > doing something with MAC address in NVS, see:
> > > https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tre
> > > e/drivers/net/wireless/ti/wlcore/boot.c#n352
> > >
> > > So... I would like to know if in wl1251 NVS calibration file is
> > > also some place for MAC address or not.
> > >
> > > Default wl1251 NVS calibration file is available in linux-firmware:
> > > https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmwar
> > > e.git/tree/ti-connectivity/wl1251-nvs.bin
> >
> > Pandora people [0] have a description of the format at [1].
> >
> > [0] https://pandorawiki.org/WiFi
> > [1] http://notaz.gp2x.de/misc/pnd/wl1251/nvs_map.txt
>
> Thank you very very much!
You are welcome.
> I tried to search for something, but I have not find anything.
> In that description is something about STA mac address:
>
> 01a 6d //STA_ADDR_L Register Address. (STA MAC Address)
> 01b 54 //
> 01c 00 //STA_ADDR_L Register
> 01d 00 //
> 01e 32 //
> 01f 28 //
> 020 00 //STA_ADDR_H Register Data.
>
> STA would be abbreviation for station and so it should be really set to
> mac address of that chip?
Yes, STA is a common abbreviation:
https://en.wikipedia.org/wiki/Station_(networking)
> If yes, that could allow us to set permanent MAC address at time when
> loading & sending NVS calibration data... Exactly same as wl1271 and new
> drivers are working.
>
> I will try to play with driver if it is really truth!
Thanks for your work.
> I already looked into original TI's multiplatform HAL driver for wl1251
> chip (big mess) and found there that there is wl1251 command to read mac
> address from chip. It could be done by this wl1251 function:
>
> wl1251_cmd_interrogate(wl, DOT11_STATION_ID, mac, sizeof(*mac))
>
> (same id as for setting permanent mac address, but opposite to read it)
-- Sebastian
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: wl1251 NVS calibration data format
From: Pali Rohár @ 2016-12-17 11:14 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Gery Kahn, Shahar Lev, Kalle Valo, linux-wireless, linux-kernel,
Pavel Machek, Ivaylo Dimitrov
In-Reply-To: <20161217093705.p64yzumqlu3u5aq7@earth>
[-- Attachment #1: Type: Text/Plain, Size: 2326 bytes --]
On Saturday 17 December 2016 10:37:05 Sebastian Reichel wrote:
> Hi,
>
> On Fri, Dec 16, 2016 at 12:01:48PM +0100, Pali Rohár wrote:
> > Hi! Do you know format of wl1251 NVS calibration data file?
> >
> > I found that there is tool for changing NVS file for wl1271 and
> > newer chips (so not for wl1251!) at:
> > https://github.com/gxk/ti-utils
> >
> > And wl1271 has in NVS data already place for MAC address. And in
> > wlcore (for wl1271 and newer) there is really kernel code which is
> > doing something with MAC address in NVS, see:
> > https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tre
> > e/drivers/net/wireless/ti/wlcore/boot.c#n352
> >
> > So... I would like to know if in wl1251 NVS calibration file is
> > also some place for MAC address or not.
> >
> > Default wl1251 NVS calibration file is available in linux-firmware:
> > https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmwar
> > e.git/tree/ti-connectivity/wl1251-nvs.bin
>
> Pandora people [0] have a description of the format at [1].
>
> [0] https://pandorawiki.org/WiFi
> [1] http://notaz.gp2x.de/misc/pnd/wl1251/nvs_map.txt
Thank you very very much!
I tried to search for something, but I have not find anything.
In that description is something about STA mac address:
01a 6d //STA_ADDR_L Register Address. (STA MAC Address)
01b 54 //
01c 00 //STA_ADDR_L Register
01d 00 //
01e 32 //
01f 28 //
020 00 //STA_ADDR_H Register Data.
STA would be abbreviation for station and so it should be really set to
mac address of that chip?
If yes, that could allow us to set permanent MAC address at time when
loading & sending NVS calibration data... Exactly same as wl1271 and new
drivers are working.
I will try to play with driver if it is really truth!
I already looked into original TI's multiplatform HAL driver for wl1251
chip (big mess) and found there that there is wl1251 command to read mac
address from chip. It could be done by this wl1251 function:
wl1251_cmd_interrogate(wl, DOT11_STATION_ID, mac, sizeof(*mac))
(same id as for setting permanent mac address, but opposite to read it)
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: wl1251 NVS calibration data format
From: Sebastian Reichel @ 2016-12-17 9:37 UTC (permalink / raw)
To: Pali Rohár
Cc: Gery Kahn, Shahar Lev, Kalle Valo, linux-wireless, linux-kernel,
Pavel Machek, Ivaylo Dimitrov
In-Reply-To: <201612161201.48356@pali>
[-- Attachment #1: Type: text/plain, Size: 1056 bytes --]
Hi,
On Fri, Dec 16, 2016 at 12:01:48PM +0100, Pali Rohár wrote:
> Hi! Do you know format of wl1251 NVS calibration data file?
>
> I found that there is tool for changing NVS file for wl1271 and newer
> chips (so not for wl1251!) at: https://github.com/gxk/ti-utils
>
> And wl1271 has in NVS data already place for MAC address. And in wlcore
> (for wl1271 and newer) there is really kernel code which is doing
> something with MAC address in NVS, see:
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ti/wlcore/boot.c#n352
>
> So... I would like to know if in wl1251 NVS calibration file is also
> some place for MAC address or not.
>
> Default wl1251 NVS calibration file is available in linux-firmware:
> https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/tree/ti-connectivity/wl1251-nvs.bin
Pandora people [0] have a description of the format at [1].
[0] https://pandorawiki.org/WiFi
[1] http://notaz.gp2x.de/misc/pnd/wl1251/nvs_map.txt
-- Sebastian
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [Patch] NFC: trf7970a:
From: Mark Greer @ 2016-12-16 20:35 UTC (permalink / raw)
To: Geoff Lansberry
Cc: linux-wireless, Lauro Ramos Venancio, Aloisio Almeida Jr,
Samuel Ortiz, Justin Bronder
In-Reply-To: <20161216045210.GA29196@animalcreek.com>
On Thu, Dec 15, 2016 at 09:52:10PM -0700, Mark Greer wrote:
> On Wed, Dec 14, 2016 at 03:31:23PM -0700, Mark Greer wrote:
> > I'll start on this
> > tonight but won't likely get far until tomorrow. In the meantime,
> > if you and/or your contractor make progress, please share.
>
> Geoff,
>
> Which version of neard are you using? 0.16?
Also, the flood.py script doesn't work well at all for me. At best,
it works successfully for one iteration and then fails continually for
all other iterations. This is true when using the trf7970a and pn533
drivers.
I've tweaked it a but but still no success. I haven't looked all that
closely at it but since you said you were persuing this, I'll wait to
hear more from you.
Mark
--
^ permalink raw reply
* Re: [PATCH 03/14 V2] rtlwifi: rtl8821ae: Remove all instances of DBG_EMERG
From: Joe Perches @ 2016-12-16 19:34 UTC (permalink / raw)
To: Larry Finger, kvalo; +Cc: devel, linux-wireless, Ping-Ke Shih
In-Reply-To: <20161215182310.13713-4-Larry.Finger@lwfinger.net>
On Thu, 2016-12-15 at 12:22 -0600, Larry Finger wrote:
> This is a step toward eliminating the RT_TRACE macros. Those calls that
> have DBG_EMERG as the level are always logged, and they represent error
> conditions, thus they are replaced with pr_err().
OK,
> diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c
[]
> @@ -162,8 +161,8 @@ static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw)
> goto exit;
> }
>
> - RT_TRACE(rtlpriv, COMP_FW, DBG_EMERG,
> - "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
> + pr_err("Checksum report OK! REG_MCUFWDL:0x%08x\n",
> + value32);
>
> value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
> value32 |= MCUFWDL_RDY;
> @@ -186,9 +184,8 @@ static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw)
> udelay(FW_8821AE_POLLING_DELAY);
> } while (counter++ < FW_8821AE_POLLING_TIMEOUT_COUNT);
>
> - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
> - "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
> - value32);
> + pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
> + value32);
It's odd to fix / remove " .\n" above but here and
the wrapping comment on the first patch applies too.
I didn't look at the rest and I won't comment on
other uses in any further patches in the series.
Thanks, Joe
^ permalink raw reply
* Re: [PATCH 02/14 V2] rtlwifi: Remove RT_TRACE messages that use DBG_EMERG
From: Joe Perches @ 2016-12-16 19:31 UTC (permalink / raw)
To: Larry Finger, kvalo; +Cc: devel, linux-wireless, Ping-Ke Shih
In-Reply-To: <20161215182310.13713-3-Larry.Finger@lwfinger.net>
On Thu, 2016-12-15 at 12:22 -0600, Larry Finger wrote:
> These messages are always logged and represent error conditions, thus
> we can use pr_err().
OK and some trivialities:
> diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c
[]
> @@ -389,8 +388,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
> /* <4> set mac->sband to wiphy->sband */
> hw->wiphy->bands[NL80211_BAND_5GHZ] = sband;
> } else {
> - RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Err BAND %d\n",
> - rtlhal->current_bandtype);
> + pr_err("Err BAND %d\n",
> + rtlhal->current_bandtype);
It's nice to rewrap lines to 80 columns where possible.
> @@ -1886,8 +1883,7 @@ void rtl_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
> (u8 *)&iotype);
> break;
> default:
> - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
> - "Unknown Scan Backup operation.\n");
> + pr_err("Unknown Scan Backup operation.\n");
And it's also nice to remove unnecessary periods for
output message consistency. Most don't use it.
> diff --git a/drivers/net/wireless/realtek/rtlwifi/cam.c b/drivers/net/wireless/realtek/rtlwifi/cam.c
[]
> @@ -285,8 +285,7 @@ u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr)
> u8 i, *addr;
>
> if (NULL == sta_addr) {
> - RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
> - "sta_addr is NULL.\n");
> + pr_err("sta_addr is NULL.\n");
etc...
^ permalink raw reply
* "rfkill: Add rfkill-any LED trigger" causes deadlock
From: Mike Krinkin @ 2016-12-16 17:09 UTC (permalink / raw)
To: kernel, johannes.berg, linux-wireless, davem, netdev
In-Reply-To: <CACpa5=_chGuU3zVcVR3nkNySwz1cGAQTs39v+BjwcDNSvOqhTw@mail.gmail.com>
On Fri, Dec 16, 2016 at 07:46:06PM +0300, Михаил Кринкин wrote:
> Hi,
>
> with recent i can't load my thinkpad with recent linux-next, bisect points
> at the commit 73f4f76a196d7adb ("rfkill: Add rfkill-any LED trigger").
>
> Problem occurs because thinkapd_acpi rfkill set_block handler
> tpacpi_rfk_hook_set_block calls rfkill_set_sw_state, which in turn calls
> new rfkill_any_led_trigger_event. So when rfkill_set_block called from
> rfkill_register we have deadlock.
>
> I added WARN to __rfkill_any_led_trigger_event to see how deadlock occurs,
> here is backtrace:
>
> [ 6.090079] WARNING: CPU: 2 PID: 307 at net/rfkill/core.c:184
> rfkill_any_led_trigger_event+0x2d/0x40
> [ 6.090080] reached __rfkill_any_led_trigger_event
> [ 6.090081] Modules linked in:
> [ 6.090082] snd_pcm sg thinkpad_acpi(+) mei_me nvram snd_seq mei
> idma64 virt_dma intel_pch_thermal ucsi intel_lpss_pci snd_seq_device
> hci_uart snd_timer snd btbcm soundcore btqca led_class btintel
> bluetooth i8042 rtc_cmos serio evdev intel_lpss_acpi intel_lpss
> acpi_pad tpm_infineon mfd_core kvm_intel kvm irqbypass ipv6 autofs4
> ext4 jbd2 mbcache sd_mod i915 i2c_algo_bit drm_kms_helper syscopyarea
> sysfillrect sysimgblt fb_sys_fops drm ahci libahci video
> pinctrl_sunrisepoint pinctrl_intel
> [ 6.090112] CPU: 2 PID: 307 Comm: systemd-udevd Tainted: G W
> 4.9.0-01741-g73f4f76-dirty #106
> [ 6.090113] Hardware name: LENOVO 20GJ004ERT/20GJ004ERT, BIOS
> R0CET21W (1.09 ) 03/07/2016
> [ 6.090114] ffffb199c023f998 ffffffffb4334b6b ffffb199c023f9e8
> 0000000000000000
> [ 6.090117] ffffb199c023f9d8 ffffffffb40658ab 000000b84dd75d28
> 0000000080000006
> [ 6.090119] ffff99ea4dd75d28 0000000000000001 0000000000000001
> 0000000000000000
> [ 6.090122] Call Trace:
> [ 6.090126] [<ffffffffb4334b6b>] dump_stack+0x4d/0x72
> [ 6.090128] [<ffffffffb40658ab>] __warn+0xcb/0xf0
> [ 6.090130] [<ffffffffb406592f>] warn_slowpath_fmt+0x5f/0x80
> [ 6.090132] [<ffffffffb4631bfd>] rfkill_any_led_trigger_event+0x2d/0x40
> [ 6.090135] [<ffffffffb46322d9>] rfkill_set_sw_state+0x89/0xd0
> [ 6.090142] [<ffffffffc06c9921>]
> tpacpi_rfk_update_swstate+0x31/0x50 [thinkpad_acpi]
> [ 6.090148] [<ffffffffc06c9972>]
> tpacpi_rfk_hook_set_block+0x32/0x70 [thinkpad_acpi]
> [ 6.090150] [<ffffffffb46327f0>] rfkill_set_block+0x90/0x160
> [ 6.090152] [<ffffffffb4632930>] __rfkill_switch_all+0x70/0xa0
> [ 6.090154] [<ffffffffb4633028>] rfkill_register+0x278/0x2b0
> [ 6.090159] [<ffffffffc06e1f0e>] tpacpi_new_rfkill+0xef/0x15d
> [thinkpad_acpi]
> [ 6.090164] [<ffffffffc06e2407>] bluetooth_init+0x15e/0x1a9 [thinkpad_acpi]
> [ 6.090169] [<ffffffffc06e2fb5>]
> thinkpad_acpi_module_init.part.47+0x5e7/0x996 [thinkpad_acpi]
> [ 6.090174] [<ffffffffc06e3364>] ?
> thinkpad_acpi_module_init.part.47+0x996/0x996 [thinkpad_acpi]
> [ 6.090179] [<ffffffffc06e36af>]
> thinkpad_acpi_module_init+0x34b/0xc9c [thinkpad_acpi]
> [ 6.090181] [<ffffffffb4000450>] do_one_initcall+0x50/0x180
> [ 6.090184] [<ffffffffb4177e12>] ? do_init_module+0x27/0x1ee
> [ 6.090186] [<ffffffffb41cc4b6>] ? kmem_cache_alloc_trace+0x156/0x1a0
> [ 6.090188] [<ffffffffb4177e4a>] do_init_module+0x5f/0x1ee
> [ 6.090191] [<ffffffffb40ed562>] load_module+0x22c2/0x28d0
> [ 6.090192] [<ffffffffb40ea0f0>] ? __symbol_put+0x60/0x60
> [ 6.090195] [<ffffffffb42ee15d>] ? ima_post_read_file+0x7d/0xa0
> [ 6.090198] [<ffffffffb42a809b>] ? security_kernel_post_read_file+0x6b/0x80
> [ 6.090200] [<ffffffffb40eddcf>] SYSC_finit_module+0xdf/0x110
> [ 6.090202] [<ffffffffb40ede1e>] SyS_finit_module+0xe/0x10
> [ 6.090204] [<ffffffffb463d524>] entry_SYSCALL_64_fastpath+0x17/0x98
> [ 6.090206] ---[ end trace ea6da61c1ec208d1 ]---
> [ 6.090207] rfkill_any_led_trigger unlocked
> [ 6.091664] ------------[ cut here ]------------
^ permalink raw reply
* "rfkill: Add rfkill-any LED trigger" causes deadlock
From: Михаил Кринкин @ 2016-12-16 16:46 UTC (permalink / raw)
To: kernel, johannes.berg, linux-wireless, davem, netdev
In-Reply-To: <20161216163707.GA2629@gmail.com>
Hi,
with recent i can't load my thinkpad with recent linux-next, bisect points
at the commit 73f4f76a196d7adb ("rfkill: Add rfkill-any LED trigger").
Problem occurs because thinkapd_acpi rfkill set_block handler
tpacpi_rfk_hook_set_block calls rfkill_set_sw_state, which in turn calls
new rfkill_any_led_trigger_event. So when rfkill_set_block called from
rfkill_register we have deadlock.
I added WARN to __rfkill_any_led_trigger_event to see how deadlock occurs,
here is backtrace:
[ 6.090079] WARNING: CPU: 2 PID: 307 at net/rfkill/core.c:184
rfkill_any_led_trigger_event+0x2d/0x40
[ 6.090080] reached __rfkill_any_led_trigger_event
[ 6.090081] Modules linked in:
[ 6.090082] snd_pcm sg thinkpad_acpi(+) mei_me nvram snd_seq mei
idma64 virt_dma intel_pch_thermal ucsi intel_lpss_pci snd_seq_device
hci_uart snd_timer snd btbcm soundcore btqca led_class btintel
bluetooth i8042 rtc_cmos serio evdev intel_lpss_acpi intel_lpss
acpi_pad tpm_infineon mfd_core kvm_intel kvm irqbypass ipv6 autofs4
ext4 jbd2 mbcache sd_mod i915 i2c_algo_bit drm_kms_helper syscopyarea
sysfillrect sysimgblt fb_sys_fops drm ahci libahci video
pinctrl_sunrisepoint pinctrl_intel
[ 6.090112] CPU: 2 PID: 307 Comm: systemd-udevd Tainted: G W
4.9.0-01741-g73f4f76-dirty #106
[ 6.090113] Hardware name: LENOVO 20GJ004ERT/20GJ004ERT, BIOS
R0CET21W (1.09 ) 03/07/2016
[ 6.090114] ffffb199c023f998 ffffffffb4334b6b ffffb199c023f9e8
0000000000000000
[ 6.090117] ffffb199c023f9d8 ffffffffb40658ab 000000b84dd75d28
0000000080000006
[ 6.090119] ffff99ea4dd75d28 0000000000000001 0000000000000001
0000000000000000
[ 6.090122] Call Trace:
[ 6.090126] [<ffffffffb4334b6b>] dump_stack+0x4d/0x72
[ 6.090128] [<ffffffffb40658ab>] __warn+0xcb/0xf0
[ 6.090130] [<ffffffffb406592f>] warn_slowpath_fmt+0x5f/0x80
[ 6.090132] [<ffffffffb4631bfd>] rfkill_any_led_trigger_event+0x2d/0x40
[ 6.090135] [<ffffffffb46322d9>] rfkill_set_sw_state+0x89/0xd0
[ 6.090142] [<ffffffffc06c9921>]
tpacpi_rfk_update_swstate+0x31/0x50 [thinkpad_acpi]
[ 6.090148] [<ffffffffc06c9972>]
tpacpi_rfk_hook_set_block+0x32/0x70 [thinkpad_acpi]
[ 6.090150] [<ffffffffb46327f0>] rfkill_set_block+0x90/0x160
[ 6.090152] [<ffffffffb4632930>] __rfkill_switch_all+0x70/0xa0
[ 6.090154] [<ffffffffb4633028>] rfkill_register+0x278/0x2b0
[ 6.090159] [<ffffffffc06e1f0e>] tpacpi_new_rfkill+0xef/0x15d
[thinkpad_acpi]
[ 6.090164] [<ffffffffc06e2407>] bluetooth_init+0x15e/0x1a9 [thinkpad_acpi]
[ 6.090169] [<ffffffffc06e2fb5>]
thinkpad_acpi_module_init.part.47+0x5e7/0x996 [thinkpad_acpi]
[ 6.090174] [<ffffffffc06e3364>] ?
thinkpad_acpi_module_init.part.47+0x996/0x996 [thinkpad_acpi]
[ 6.090179] [<ffffffffc06e36af>]
thinkpad_acpi_module_init+0x34b/0xc9c [thinkpad_acpi]
[ 6.090181] [<ffffffffb4000450>] do_one_initcall+0x50/0x180
[ 6.090184] [<ffffffffb4177e12>] ? do_init_module+0x27/0x1ee
[ 6.090186] [<ffffffffb41cc4b6>] ? kmem_cache_alloc_trace+0x156/0x1a0
[ 6.090188] [<ffffffffb4177e4a>] do_init_module+0x5f/0x1ee
[ 6.090191] [<ffffffffb40ed562>] load_module+0x22c2/0x28d0
[ 6.090192] [<ffffffffb40ea0f0>] ? __symbol_put+0x60/0x60
[ 6.090195] [<ffffffffb42ee15d>] ? ima_post_read_file+0x7d/0xa0
[ 6.090198] [<ffffffffb42a809b>] ? security_kernel_post_read_file+0x6b/0x80
[ 6.090200] [<ffffffffb40eddcf>] SYSC_finit_module+0xdf/0x110
[ 6.090202] [<ffffffffb40ede1e>] SyS_finit_module+0xe/0x10
[ 6.090204] [<ffffffffb463d524>] entry_SYSCALL_64_fastpath+0x17/0x98
[ 6.090206] ---[ end trace ea6da61c1ec208d1 ]---
[ 6.090207] rfkill_any_led_trigger unlocked
[ 6.091664] ------------[ cut here ]------------
^ permalink raw reply
* Re: [RFC V3 04/11] nl80211: add driver api for gscan notifications
From: Johannes Berg @ 2016-12-16 12:36 UTC (permalink / raw)
To: Arend Van Spriel; +Cc: linux-wireless
In-Reply-To: <9715e731-efcc-0252-ed7b-5ca67e2c0b5b@broadcom.com>
On Fri, 2016-12-16 at 13:17 +0100, Arend Van Spriel wrote:
>
> > I have no problem introducing a common storage for this, if
> > necessary with some fields/nl attributes being optional, but I
> > suspect this is actually a necessary part of gscan, otherwise
> > you're not able to report all the necessary data?
>
> If you just look at the gscan api in wifihal then yes. I was just
> wondering whether "all the necessary data" really comprises all these
> from a use-case perspective. As an example the api also has rtt
> fields, but both brcm and intel solutions do not report that.
Yeah, no idea. Sorry - my wording wasn't quite precise. By "this is
actually a necessary part of gscan" I meant the partial history
reporting itself, not any particular field thereof.
johannes
^ permalink raw reply
* pull-request: mac80211 2016-12-16
From: Johannes Berg @ 2016-12-16 12:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-wireless
Hi Dave,
Since you seem to be updating net, I thought I'd send you a few fixes.
These aren't really all that important though, so if you want to let
them wait for a bit I can live with that.
Please pull and let me know if there's any problem.
Thanks,
johannes
The following changes since commit 8fa3b6f9392bf6d90cb7b908e07bd90166639f0a:
Merge tag 'cris-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jesper/cris (2016-12-12 09:06:38 -0800)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git tags/mac80211-for-davem-2016-12-16
for you to fetch changes up to a17d93ff3a950fefaea40e4a4bf3669b9137c533:
mac80211: fix legacy and invalid rx-rate report (2016-12-15 10:54:48 +0100)
----------------------------------------------------------------
Three fixes:
* avoid a WARN_ON() when trying to use WEP with AP_VLANs
* ensure enough headroom on mesh forwarding packets
* don't report unknown/invalid rates to userspace
----------------------------------------------------------------
Ben Greear (1):
mac80211: fix legacy and invalid rx-rate report
Cedric Izoard (1):
mac80211: Ensure enough headroom when forwarding mesh pkt
Johannes Berg (1):
mac80211: don't call drv_set_default_unicast_key() for VLANs
net/mac80211/key.c | 3 ++-
net/mac80211/rx.c | 2 +-
net/mac80211/sta_info.c | 14 ++++++++------
3 files changed, 11 insertions(+), 8 deletions(-)
^ permalink raw reply
* Re: [PATCH] nl80211: better describe field in struct nl80211_bss_select_rssi_adjust
From: Johannes Berg @ 2016-12-16 12:33 UTC (permalink / raw)
To: Arend van Spriel; +Cc: linux-wireless
In-Reply-To: <1481890554-18019-1-git-send-email-arend.vanspriel@broadcom.com>
On Fri, 2016-12-16 at 12:15 +0000, Arend van Spriel wrote:
> The two fields in struct nl80211_bss_select_rssi_adjust did not state
> their type or unit. Adding documentation.
>
Applied, thanks :)
johannes
^ permalink raw reply
* Re: [PATCH] nl80211: rework {sched_,}scan event related functions
From: Johannes Berg @ 2016-12-16 12:34 UTC (permalink / raw)
To: Arend van Spriel; +Cc: linux-wireless
In-Reply-To: <1481887314-9471-1-git-send-email-arend.vanspriel@broadcom.com>
On Fri, 2016-12-16 at 11:21 +0000, Arend van Spriel wrote:
> A couple of functions used with scan events were named with
> term "send" although they were only preparing the the event
> message so renamed those.
Applied - I added a mention of nl80211_send_sched_scan_results() to the
commit log since I was confused about that at first :)
johannes
^ permalink raw reply
* Re: [RFC V3 03/11] nl80211: add support for gscan
From: Arend Van Spriel @ 2016-12-16 12:21 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1481883237.27953.22.camel@sipsolutions.net>
On 16-12-2016 11:13, Johannes Berg wrote:
> On Wed, 2016-12-14 at 10:01 +0100, Arend Van Spriel wrote:
>
>> Had to look for "> 16" ;-)
>
> Sorry.
>
>> Here an instance of the tab vs. space issue you mentioned. Will go
>> over the patch and fix that.
>
> There were a few, not really interesting though - git would probably
> flag it anyway, or checkpatch :)
>
>>> + if (num_chans > 16)
>>> + return -EINVAL;
>>
>> I suspect this is the restriction you were referring to.
>
> Yes.
>
>> There is no
>> reason for this although the android wifi hal has max 16 channels in
>> a bucket so I might have picked that up.
>
> I thought I saw something with a u16 bitmap that seemed related, but I
> don't see that now so I'm probably just confused.
>
>> So could a driver have a similar limit and should we add such to the
>> gscan capabilities? For instance our firmware api has a nasty
>> restriction of 64 channels for all buckets together, eg. can do 4
>> buckets of 16 channels each.
>
> We do have a limit of the maximum scan buckets, which seems to be 16
> right now. We also have a limit on the number of channels per bucket,
> which is also 16, but no combined limit afaict (so 16x16 seems fine).
>
> Maybe we do need some advertisement in that area then? Right now,
> wifihal seems to be able to read as capabilities the number of buckets
> (wifi_gscan_capabilities), but assumes the number of channels:
>
> const unsigned MAX_CHANNELS = 16;
> const unsigned MAX_BUCKETS = 16;
>
> I guess we took that and combined it, and you had more negotiation with
> Google ;-)
I was not so much involved with the initial gscan effort, but I guess
for brcm it might be true.
> We may then have to actually advertise the limit you have ("64 channels
> combined over all buckets"), unless you can get away with just
> advertising 4 buckets (and us saying 16 channels per bucket is enough?)
>
> I'm a bit tempted to make this more forward compatible though and not
> hard-limit the number of channels per bucket in the code.
Indeed so I will remove it.
Regards,
Arend
^ permalink raw reply
* Re: [RFC V3 04/11] nl80211: add driver api for gscan notifications
From: Arend Van Spriel @ 2016-12-16 12:17 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1481882578.27953.20.camel@sipsolutions.net>
On 16-12-2016 11:02, Johannes Berg wrote:
>
>> Not sure what is meant by "through the buckets".
>
> TBH, I was handwaving because I don't understand this part of gscan
> well :-)
>
>> Referring to your
>> remark/question in the "Unversal scan proposal" thread:
>>
>> """
>> I'm much more worried about the "bucket reporting" since that doesn't
>> fit into the current full BSS reporting model at all. What's your
>> suggestion for this?
>> """
>>
>> So this is exactly the dilemma I considered so I decided to stick
>> with the full BSS reporting model for gscan as well merely to get it
>> discussed so glad you brought it up ;-).
>
> Heh.
>
> Ok, so I missed that. Somehow I thought hidden in the buckets was a
> partial reporting :-)
>
>> The problem here is that gscan is a vehicle that serves a number of
>> use-cases. So ignoring hotlists, ePNO, etc. the gscan configuration
>> still hold several notification types:
>>
>> - report after completing M scans capturing N best APs or a
>> percentage of (M * N).
>> - report after completing a scan include a specific bucket.
>> - report full scan results.
>>
>> The first two notification trigger retrieval of gscan results which
>> are historic, ie. partial scan results for max M scans.
>>
>> As said earlier the universal scan proposal has some similarities to
>> gscan. Guess you share that as you are using the term "bucket
>> reporting" in that discussion ;-). The historic results are needed
>> for location (if I am not mistaken) so the full BSS reporting model
>> does not fit that. Question is what particular attribute in the
>> historic results is needed for location (suspecting only rssi and
>> possibly the timestamp, but would like to see that confirmed). I was
>> thinking about have historic storage in cfg80211 so we do not need a
>> per-driver solution.
>
> Ok, now I'm starting to understand this better, I guess.
>
> As far as I can tell from our code, for cached results we're reporting
> the following data:
>
> * some flags
> * a scan ID
> * and for each AP:
> * RSSI
> * timestamp
> * channel
> * BSSID
> * SSID (which internally we even have a separate table for and each
> AP just has an index to it, to save memory I guess)
> * beacon period
> * capability field
>
> No IEs and similar things like differentiating probe response/beacon,
> so we can't use the full reporting for this.
>
> I have no problem introducing a common storage for this, if necessary
> with some fields/nl attributes being optional, but I suspect this is
> actually a necessary part of gscan, otherwise you're not able to report
> all the necessary data?
If you just look at the gscan api in wifihal then yes. I was just
wondering whether "all the necessary data" really comprises all these
from a use-case perspective. As an example the api also has rtt fields,
but both brcm and intel solutions do not report that.
Regards,
Arend
^ permalink raw reply
* [PATCH] nl80211: better describe field in struct nl80211_bss_select_rssi_adjust
From: Arend van Spriel @ 2016-12-16 12:15 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
The two fields in struct nl80211_bss_select_rssi_adjust did not state
their type or unit. Adding documentation.
Reported-by: Jouni Malinen <j@w1.fi>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
include/uapi/linux/nl80211.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 6b76e3b..d74e10b 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4964,8 +4964,9 @@ enum nl80211_sched_scan_plan {
/**
* struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters.
*
- * @band: band of BSS that must match for RSSI value adjustment.
- * @delta: value used to adjust the RSSI value of matching BSS.
+ * @band: band of BSS that must match for RSSI value adjustment. The value
+ * of this field is according to &enum nl80211_band.
+ * @delta: value used to adjust the RSSI value of matching BSS in dB.
*/
struct nl80211_bss_select_rssi_adjust {
__u8 band;
--
1.9.1
^ permalink raw reply related
* [PATCH] nl80211: rework {sched_,}scan event related functions
From: Arend van Spriel @ 2016-12-16 11:21 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
A couple of functions used with scan events were named with
term "send" although they were only preparing the the event
message so renamed those.
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
net/wireless/nl80211.c | 34 ++++++++--------------------------
net/wireless/nl80211.h | 6 ++----
net/wireless/scan.c | 9 +++++----
3 files changed, 15 insertions(+), 34 deletions(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3df85a7..727ca50 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -12810,7 +12810,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
return -ENOBUFS;
}
-static int nl80211_send_scan_msg(struct sk_buff *msg,
+static int nl80211_prep_scan_msg(struct sk_buff *msg,
struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
u32 portid, u32 seq, int flags,
@@ -12841,7 +12841,7 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
}
static int
-nl80211_send_sched_scan_msg(struct sk_buff *msg,
+nl80211_prep_sched_scan_msg(struct sk_buff *msg,
struct cfg80211_registered_device *rdev,
struct net_device *netdev,
u32 portid, u32 seq, int flags, u32 cmd)
@@ -12873,7 +12873,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
if (!msg)
return;
- if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
+ if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_TRIGGER_SCAN) < 0) {
nlmsg_free(msg);
return;
@@ -12892,7 +12892,7 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
if (!msg)
return NULL;
- if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
+ if (nl80211_prep_scan_msg(msg, rdev, wdev, 0, 0, 0,
aborted ? NL80211_CMD_SCAN_ABORTED :
NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
nlmsg_free(msg);
@@ -12902,31 +12902,13 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
return msg;
}
-void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
- struct sk_buff *msg)
-{
- if (!msg)
- return;
-
- genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
- NL80211_MCGRP_SCAN, GFP_KERNEL);
-}
-
-void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
- struct net_device *netdev)
+/* send message created by nl80211_build_scan_msg() */
+void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
+ struct sk_buff *msg)
{
- struct sk_buff *msg;
-
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return;
- if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
- NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
- nlmsg_free(msg);
- return;
- }
-
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_SCAN, GFP_KERNEL);
}
@@ -12940,7 +12922,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
if (!msg)
return;
- if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
+ if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
nlmsg_free(msg);
return;
}
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 7e3821d..75f8252 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -14,12 +14,10 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, bool aborted);
-void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
- struct sk_buff *msg);
+void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
+ struct sk_buff *msg);
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 cmd);
-void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
- struct net_device *netdev);
void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
struct regulatory_request *request);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index b5bd58d..76cdd1d 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -176,7 +176,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
ASSERT_RTNL();
if (rdev->scan_msg) {
- nl80211_send_scan_result(rdev, rdev->scan_msg);
+ nl80211_send_scan_msg(rdev, rdev->scan_msg);
rdev->scan_msg = NULL;
return;
}
@@ -222,7 +222,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
if (!send_message)
rdev->scan_msg = msg;
else
- nl80211_send_scan_result(rdev, msg);
+ nl80211_send_scan_msg(rdev, msg);
}
void __cfg80211_scan_done(struct work_struct *wk)
@@ -270,7 +270,8 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
spin_unlock_bh(&rdev->bss_lock);
request->scan_start = jiffies;
}
- nl80211_send_sched_scan_results(rdev, request->dev);
+ nl80211_send_sched_scan(rdev, request->dev,
+ NL80211_CMD_SCHED_SCAN_RESULTS);
}
rtnl_unlock();
@@ -1078,7 +1079,7 @@ struct cfg80211_bss *
else
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
rcu_assign_pointer(tmp.pub.ies, ies);
-
+
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
tmp.pub.channel = channel;
tmp.pub.scan_width = data->scan_width;
--
1.9.1
^ permalink raw reply related
* Re: [RFC v2 11/11] ath10k: Added sdio support
From: Valo, Kalle @ 2016-12-16 11:21 UTC (permalink / raw)
To: Erik Stromdahl; +Cc: linux-wireless@vger.kernel.org, ath10k@lists.infradead.org
In-Reply-To: <1479496971-19174-12-git-send-email-erik.stromdahl@gmail.com>
Erik Stromdahl <erik.stromdahl@gmail.com> writes:
> Initial HIF sdio/mailbox implementation.
>
> Signed-off-by: Erik Stromdahl <erik.stromdahl@gmail.com>
I know most of this coming from ath6kl but I think we should still
improve the code. Lots of comments will follow, don't get scared :)
> +#define CALC_TXRX_PADDED_LEN(ar_sdio, len) \
> + (__ALIGN_MASK((len), (ar_sdio)->mbox_info.block_mask))
I think this could be a proper static inline function. Andrew Morton
once said: "Write in C, not CPP" (or something like that), I think
that's a really good point.
> +static int ath10k_sdio_read_write_sync(struct ath10k *ar, u32 addr, u8 *=
buf,
> + u32 len, u32 request);
> +static int ath10k_sdio_hif_diag_read(struct ath10k *ar, u32 address, voi=
d *buf,
> + size_t buf_len);
> +static int ath10k_sdio_hif_diag_read32(struct ath10k *ar, u32 address,
> + u32 *value);
We prefer to avoid forward declarations if at all possible. I didn't
check but if there's a clean way to avoid these please remove them.
> +/* HIF mbox interrupt handling */
> +
> +static int ath10k_sdio_mbox_rx_process_packet(struct ath10k_sdio *ar_sdi=
o,
> + struct ath10k_sdio_rx_data *pkt,
> + u32 *lookaheads,
> + int *n_lookaheads)
> +{
So the style in ath10k is that all functions (of course this doesn't
apply to callbacks etc) have "struct ath10k *ar" as the first parameter.
This way there's no need to check if a function takes ar or ar_sdio.
> + int status =3D 0;
In ath10k we prefer to use ret. And avoid initialising it, please.
> + struct ath10k_htc *htc =3D &ar_sdio->ar->htc;
> + struct sk_buff *skb =3D pkt->skb;
> + struct ath10k_htc_hdr *htc_hdr =3D (struct ath10k_htc_hdr *)skb->data;
> + bool trailer_present =3D htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESE=
NT;
> + u16 payload_len;
> +
> + payload_len =3D le16_to_cpu(htc_hdr->len);
> +
> + if (trailer_present) {
> + u8 *trailer;
> + enum ath10k_htc_ep_id eid;
> +
> + trailer =3D skb->data + sizeof(struct ath10k_htc_hdr) +
> + payload_len - htc_hdr->trailer_len;
> +
> + eid =3D (enum ath10k_htc_ep_id)htc_hdr->eid;
A some kind of mapping function for ep id would be nice, it makes it
more visible how it works.
> +static int ath10k_sdio_mbox_rx_process_packets(struct ath10k_sdio *ar_sd=
io,
> + u32 lookaheads[],
> + int *n_lookahead)
> +{
> + struct ath10k *ar =3D ar_sdio->ar;
> + struct ath10k_htc *htc =3D &ar->htc;
> + struct ath10k_sdio_rx_data *pkt;
> + int status =3D 0, i;
> +
> + for (i =3D 0; i < ar_sdio->n_rx_pkts; i++) {
> + struct ath10k_htc_ep *ep;
> + enum ath10k_htc_ep_id id;
> + u32 *lookaheads_local =3D lookaheads;
> + int *n_lookahead_local =3D n_lookahead;
> +
> + id =3D ((struct ath10k_htc_hdr *)&lookaheads[i])->eid;
> +
> + if (id >=3D ATH10K_HTC_EP_COUNT) {
> + ath10k_err(ar, "Invalid endpoint in look-ahead: %d\n",
> + id);
In ath10k we use ath10k_err() for errors from which can't survive and
ath10k_warn() for errors where we try to continue. So ath10k_warn()
would be more approriate here and most of other cases in sdio.c
> + status =3D -ENOMEM;
> + goto out;
> + }
> +
> + ep =3D &htc->endpoint[id];
> +
> + if (ep->service_id =3D=3D 0) {
> + ath10k_err(ar, "ep %d is not connected !\n", id);
> + status =3D -ENOMEM;
> + goto out;
> + }
> +
> + pkt =3D &ar_sdio->rx_pkts[i];
> +
> + if (pkt->part_of_bundle && !pkt->last_in_bundle) {
> + /* Only read lookahead's from RX trailers
> + * for the last packet in a bundle.
> + */
> + lookaheads_local =3D NULL;
> + n_lookahead_local =3D NULL;
> + }
> +
> + status =3D ath10k_sdio_mbox_rx_process_packet(ar_sdio,
> + pkt,
> + lookaheads_local,
> + n_lookahead_local);
> + if (status)
> + goto out;
> +
> + ep->ep_ops.ep_rx_complete(ar_sdio->ar, pkt->skb);
> + /* The RX complete handler now owns the skb...*/
> + pkt->skb =3D NULL;
> + pkt->alloc_len =3D 0;
> + }
> +
> +out:
> + /* Free all packets that was not passed on to the RX completion
> + * handler...
> + */
> + for (; i < ar_sdio->n_rx_pkts; i++)
> + ath10k_sdio_mbox_free_rx_pkt(&ar_sdio->rx_pkts[i]);
I got a bit fooled by not initialising i here and only then realised
why. I guess it's ok but a bit of so and so
> +
> + return status;
> +}
> +
> +static int alloc_pkt_bundle(struct ath10k *ar,
> + struct ath10k_sdio_rx_data *rx_pkts,
> + struct ath10k_htc_hdr *htc_hdr,
> + size_t full_len, size_t act_len, size_t *bndl_cnt)
> +{
> + int i, status =3D 0;
> +
> + *bndl_cnt =3D (htc_hdr->flags & ATH10K_HTC_FLAG_BUNDLE_MASK) >>
> + ATH10K_HTC_FLAG_BUNDLE_LSB;
We recently got FIELD_GET() and FIELD_PREP() to kernel for handling
bitmasks. ath10k is not yet converted (patches welcome!) but it would be
good to use those already in sdio.c. Also SM() could be replaced with
those.
> +int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k_sdio *ar_sdio,
> + u32 msg_lookahead, bool *done)
> +{
> + struct ath10k *ar =3D ar_sdio->ar;
> + int status =3D 0;
> + u32 lookaheads[ATH10K_SDIO_MAX_RX_MSGS];
> + int n_lookaheads =3D 1;
> +
> + *done =3D true;
> +
> + /* Copy the lookahead obtained from the HTC register table into our
> + * temp array as a start value.
> + */
> + lookaheads[0] =3D msg_lookahead;
> +
> + for (;;) {
Iternal loops in kernel can be dangerous. Better to add some sort of
timeout check with a warning message, something like:
while ((time_before(jiffies, timeout)) {
}
if (timed out)
ath10k_warn("timeout in foo");
> + /* Try to allocate as many HTC RX packets indicated by
> + * n_lookaheads.
> + */
> + status =3D ath10k_sdio_mbox_rx_alloc(ar_sdio, lookaheads,
> + n_lookaheads);
> + if (status)
> + break;
> +
> + if (ar_sdio->n_rx_pkts >=3D 2)
> + /* A recv bundle was detected, force IRQ status
> + * re-check again.
> + */
> + *done =3D false;
> +
> + status =3D ath10k_sdio_mbox_rx_fetch(ar_sdio);
> +
> + /* Process fetched packets. This will potentially update
> + * n_lookaheads depending on if the packets contain lookahead
> + * reports.
> + */
> + n_lookaheads =3D 0;
> + status =3D ath10k_sdio_mbox_rx_process_packets(ar_sdio,
> + lookaheads,
> + &n_lookaheads);
> +
> + if (!n_lookaheads || status)
> + break;
> +
> + /* For SYNCH processing, if we get here, we are running
> + * through the loop again due to updated lookaheads. Set
> + * flag that we should re-check IRQ status registers again
> + * before leaving IRQ processing, this can net better
> + * performance in high throughput situations.
> + */
> + *done =3D false;
> + }
> +
> + if (status && (status !=3D -ECANCELED))
> + ath10k_err(ar, "failed to get pending recv messages: %d\n",
> + status);
> +
> + if (atomic_read(&ar_sdio->stopping)) {
> + ath10k_warn(ar, "host is going to stop. Turning of RX\n");
> + ath10k_sdio_hif_rx_control(ar_sdio, false);
> + }
I'm always skeptic when I use atomic variables used like this, I doubt
it's really correct.
> +
> + return status;
> +}
> +
> +static int ath10k_sdio_mbox_proc_dbg_intr(struct ath10k_sdio *ar_sdio)
> +{
> + int ret;
> + u32 dummy;
> + struct ath10k *ar =3D ar_sdio->ar;
> +
> + ath10k_warn(ar, "firmware crashed\n");
We have firmware crash dump support in ath10k. You could add a "TODO:"
comment about implementing that later.
> +static int ath10k_sdio_mbox_proc_err_intr(struct ath10k_sdio *ar_sdio)
> +{
> + int status;
> + u8 error_int_status;
> + u8 reg_buf[4];
> + struct ath10k_sdio_irq_data *irq_data =3D &ar_sdio->irq_data;
> + struct ath10k *ar =3D ar_sdio->ar;
> +
> + ath10k_dbg(ar, ATH10K_DBG_SDIO, "error interrupt\n");
> +
> + error_int_status =3D irq_data->irq_proc_reg.error_int_status & 0x0F;
> + if (!error_int_status) {
> + WARN_ON(1);
> + return -EIO;
> + }
> +
> + ath10k_dbg(ar, ATH10K_DBG_SDIO,
> + "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
> + error_int_status);
> +
> + if (MS(error_int_status, MBOX_ERROR_INT_STATUS_WAKEUP))
> + ath10k_dbg(ar, ATH10K_DBG_SDIO, "error : wakeup\n");
> +
> + if (MS(error_int_status, MBOX_ERROR_INT_STATUS_RX_UNDERFLOW))
> + ath10k_err(ar, "rx underflow\n");
> +
> + if (MS(error_int_status, MBOX_ERROR_INT_STATUS_TX_OVERFLOW))
> + ath10k_err(ar, "tx overflow\n");
> +
> + /* Clear the interrupt */
> + irq_data->irq_proc_reg.error_int_status &=3D ~error_int_status;
> +
> + /* set W1C value to clear the interrupt, this hits the register first *=
/
> + reg_buf[0] =3D error_int_status;
> + reg_buf[1] =3D 0;
> + reg_buf[2] =3D 0;
> + reg_buf[3] =3D 0;
> +
> + status =3D ath10k_sdio_read_write_sync(ar,
> + MBOX_ERROR_INT_STATUS_ADDRESS,
> + reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
> +
> + WARN_ON(status);
This is a bit dangerous, in worst case it can spam the kernel log and
force a host reboot due watchdog timing out etc.
Better to replace with standard warning message:
ret =3D ath10k_sdio_read_write_sync(ar,
MBOX_ERROR_INT_STATUS_ADDRESS,
reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
if (ret) {
ath10k_warn("failed to read interrupr status: %d", ret);
return ret;
}
> +static int ath10k_sdio_mbox_proc_cpu_intr(struct ath10k_sdio *ar_sdio)
> +{
> + int status;
> + struct ath10k_sdio_irq_data *irq_data =3D &ar_sdio->irq_data;
> + struct ath10k *ar =3D ar_sdio->ar;
> + u8 cpu_int_status, reg_buf[4];
> +
> + cpu_int_status =3D irq_data->irq_proc_reg.cpu_int_status &
> + irq_data->irq_en_reg.cpu_int_status_en;
> + if (!cpu_int_status) {
> + WARN_ON(1);
> + return -EIO;
> + }
Ditto about WARN_ON(), ath10k_warn() is much better.
> +/* process pending interrupts synchronously */
> +static int ath10k_sdio_mbox_proc_pending_irqs(struct ath10k_sdio *ar_sdi=
o,
> + bool *done)
> +{
> + struct ath10k_sdio_irq_data *irq_data =3D &ar_sdio->irq_data;
> + struct ath10k *ar =3D ar_sdio->ar;
> + struct ath10k_sdio_irq_proc_registers *rg;
> + int status =3D 0;
> + u8 host_int_status =3D 0;
> + u32 lookahead =3D 0;
> + u8 htc_mbox =3D 1 << ATH10K_HTC_MAILBOX;
> +
> + /* NOTE: HIF implementation guarantees that the context of this
> + * call allows us to perform SYNCHRONOUS I/O, that is we can block,
> + * sleep or call any API that can block or switch thread/task
> + * contexts. This is a fully schedulable context.
> + */
> +
> + /* Process pending intr only when int_status_en is clear, it may
> + * result in unnecessary bus transaction otherwise. Target may be
> + * unresponsive at the time.
> + */
> + if (irq_data->irq_en_reg.int_status_en) {
> + /* Read the first sizeof(struct ath10k_irq_proc_registers)
> + * bytes of the HTC register table. This
> + * will yield us the value of different int status
> + * registers and the lookahead registers.
> + */
> + status =3D ath10k_sdio_read_write_sync(
> + ar,
> + MBOX_HOST_INT_STATUS_ADDRESS,
> + (u8 *)&irq_data->irq_proc_reg,
> + sizeof(irq_data->irq_proc_reg),
> + HIF_RD_SYNC_BYTE_INC);
> + if (status)
> + goto out;
> +
> + /* Update only those registers that are enabled */
> + host_int_status =3D irq_data->irq_proc_reg.host_int_status &
> + irq_data->irq_en_reg.int_status_en;
> +
> + /* Look at mbox status */
> + if (host_int_status & htc_mbox) {
> + /* Mask out pending mbox value, we use look ahead as
> + * the real flag for mbox processing.
> + */
> + host_int_status &=3D ~htc_mbox;
> + if (irq_data->irq_proc_reg.rx_lookahead_valid &
> + htc_mbox) {
> + rg =3D &irq_data->irq_proc_reg;
> + lookahead =3D le32_to_cpu(
> + rg->rx_lookahead[ATH10K_HTC_MAILBOX]);
> + if (!lookahead)
> + ath10k_err(ar, "lookahead is zero!\n");
> + }
> + }
> + }
> +
> + if (!host_int_status && !lookahead) {
> + *done =3D true;
> + goto out;
> + }
> +
> + if (lookahead) {
> + ath10k_dbg(ar, ATH10K_DBG_SDIO,
> + "pending mailbox msg, lookahead: 0x%08X\n",
> + lookahead);
> +
> + status =3D ath10k_sdio_mbox_rxmsg_pending_handler(ar_sdio,
> + lookahead,
> + done);
> + if (status)
> + goto out;
> + }
> +
> + /* now, handle the rest of the interrupts */
> + ath10k_dbg(ar, ATH10K_DBG_SDIO,
> + "valid interrupt source(s) for other interrupts: 0x%x\n",
> + host_int_status);
> +
> + if (MS(host_int_status, MBOX_HOST_INT_STATUS_CPU)) {
> + /* CPU Interrupt */
> + status =3D ath10k_sdio_mbox_proc_cpu_intr(ar_sdio);
> + if (status)
> + goto out;
> + }
> +
> + if (MS(host_int_status, MBOX_HOST_INT_STATUS_ERROR)) {
> + /* Error Interrupt */
> + status =3D ath10k_sdio_mbox_proc_err_intr(ar_sdio);
> + if (status)
> + goto out;
> + }
> +
> + if (MS(host_int_status, MBOX_HOST_INT_STATUS_COUNTER))
> + /* Counter Interrupt */
> + status =3D ath10k_sdio_mbox_proc_counter_intr(ar_sdio);
> +
> +out:
> + /* An optimization to bypass reading the IRQ status registers
> + * unecessarily which can re-wake the target, if upper layers
> + * determine that we are in a low-throughput mode, we can rely on
> + * taking another interrupt rather than re-checking the status
> + * registers which can re-wake the target.
> + *
> + * NOTE : for host interfaces that makes use of detecting pending
> + * mbox messages at hif can not use this optimization due to
> + * possible side effects, SPI requires the host to drain all
> + * messages from the mailbox before exiting the ISR routine.
> + */
> +
> + ath10k_dbg(ar, ATH10K_DBG_SDIO,
> + "%s: (done:%d, status=3D%d)\n", __func__, *done, status);
We try to follow this kind of format for debug messages:
"sdio pending irqs done %d status %d"
So start with the debug level name followed by the debug separated with spa=
ces.
And IIRC no need for "\n", the macro adds that automatically.
> +
> + return status;
> +}
> +
> +/* Macro to check if DMA buffer is WORD-aligned and DMA-able.
> + * Most host controllers assume the buffer is DMA'able and will
> + * bug-check otherwise (i.e. buffers on the stack). virt_addr_valid
> + * check fails on stack memory.
> + */
> +static inline bool buf_needs_bounce(u8 *buf)
> +{
> + return ((unsigned long)buf & 0x3) || !virt_addr_valid(buf);
> +}
IS_ALIGNED()? And this is super ugly, do we really need this? I would
much prefer that we would directly use struct sk_buff, more of that
later.
> +static inline enum ath10k_htc_ep_id pipe_id_to_eid(u8 pipe_id)
> +{
> + return (enum ath10k_htc_ep_id)pipe_id;
> +}
Oh, we already have a this kind of mapping function? Can't this be used
earlier?
> +static void ath10k_sdio_set_mbox_info(struct ath10k_sdio *ar_sdio)
> +{
> + struct ath10k_mbox_info *mbox_info =3D &ar_sdio->mbox_info;
> + u16 device =3D ar_sdio->func->device;
> +
> + mbox_info->htc_addr =3D ATH10K_HIF_MBOX_BASE_ADDR;
> + mbox_info->block_size =3D ATH10K_HIF_MBOX_BLOCK_SIZE;
> + mbox_info->block_mask =3D ATH10K_HIF_MBOX_BLOCK_SIZE - 1;
> + mbox_info->gmbox_addr =3D ATH10K_HIF_GMBOX_BASE_ADDR;
> + mbox_info->gmbox_sz =3D ATH10K_HIF_GMBOX_WIDTH;
> +
> + mbox_info->ext_info[0].htc_ext_addr =3D ATH10K_HIF_MBOX0_EXT_BASE_ADDR;
> +
> + if ((device & ATH10K_MANUFACTURER_ID_REV_MASK) < 4)
> + mbox_info->ext_info[0].htc_ext_sz =3D ATH10K_HIF_MBOX0_EXT_WIDTH;
> + else
> + /* from rome 2.0(0x504), the width has been extended
> + * to 56K
> + */
> + mbox_info->ext_info[0].htc_ext_sz =3D
> + ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0;
> +
> + mbox_info->ext_info[1].htc_ext_addr =3D
> + mbox_info->ext_info[0].htc_ext_addr +
> + mbox_info->ext_info[0].htc_ext_sz +
> + ATH10K_HIF_MBOX_DUMMY_SPACE_SIZE;
> + mbox_info->ext_info[1].htc_ext_sz =3D ATH10K_HIF_MBOX1_EXT_WIDTH;
> +}
> +
> +static inline void ath10k_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw,
> + unsigned int address,
> + unsigned char val)
> +{
> + const u8 func =3D 0;
> +
> + *arg =3D ((write & 1) << 31) |
> + ((func & 0x7) << 28) |
> + ((raw & 1) << 27) |
> + (1 << 26) |
> + ((address & 0x1FFFF) << 9) |
> + (1 << 8) |
> + (val & 0xFF);
> +}
Quite ugly. FIELD_PREP() & co?
> +
> +static int ath10k_sdio_func0_cmd52_wr_byte(struct mmc_card *card,
> + unsigned int address,
> + unsigned char byte)
> +{
> + struct mmc_command io_cmd;
> +
> + memset(&io_cmd, 0, sizeof(io_cmd));
> + ath10k_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte);
> + io_cmd.opcode =3D SD_IO_RW_DIRECT;
> + io_cmd.flags =3D MMC_RSP_R5 | MMC_CMD_AC;
> +
> + return mmc_wait_for_cmd(card->host, &io_cmd, 0);
> +}
> +
> +static int ath10k_sdio_func0_cmd52_rd_byte(struct mmc_card *card,
> + unsigned int address,
> + unsigned char *byte)
> +{
> + int ret;
> + struct mmc_command io_cmd;
> +
> + memset(&io_cmd, 0, sizeof(io_cmd));
> + ath10k_sdio_set_cmd52_arg(&io_cmd.arg, 0, 0, address, 0);
> + io_cmd.opcode =3D SD_IO_RW_DIRECT;
> + io_cmd.flags =3D MMC_RSP_R5 | MMC_CMD_AC;
> +
> + ret =3D mmc_wait_for_cmd(card->host, &io_cmd, 0);
> + if (!ret)
> + *byte =3D io_cmd.resp[0];
> +
> + return ret;
> +}
> +
> +static int ath10k_sdio_io(struct ath10k_sdio *ar_sdio, u32 request, u32 =
addr,
> + u8 *buf, u32 len)
> +{
> + int ret =3D 0;
Avoid these kind of unnecessary initialisations.
> + struct sdio_func *func =3D ar_sdio->func;
> + struct ath10k *ar =3D ar_sdio->ar;
> +
> + sdio_claim_host(func);
> +
> + if (request & HIF_WRITE) {
> + if (request & HIF_FIXED_ADDRESS)
> + ret =3D sdio_writesb(func, addr, buf, len);
> + else
> + ret =3D sdio_memcpy_toio(func, addr, buf, len);
> + } else {
> + if (request & HIF_FIXED_ADDRESS)
> + ret =3D sdio_readsb(func, buf, addr, len);
> + else
> + ret =3D sdio_memcpy_fromio(func, buf, addr, len);
> + }
> +
> + sdio_release_host(func);
> +
> + ath10k_dbg(ar, ATH10K_DBG_SDIO, "%s addr 0x%x%s buf 0x%p len %d\n",
> + request & HIF_WRITE ? "wr" : "rd", addr,
> + request & HIF_FIXED_ADDRESS ? " (fixed)" : "", buf, len);
> + ath10k_dbg_dump(ar, ATH10K_DBG_SDIO_DUMP, NULL,
> + request & HIF_WRITE ? "sdio wr " : "sdio rd ",
> + buf, len);
> +
> + return ret;
> +}
> +
> +static struct ath10k_sdio_bus_request
> +*ath10k_sdio_alloc_busreq(struct ath10k_sdio *ar_sdio)
> +{
> + struct ath10k_sdio_bus_request *bus_req;
> +
> + spin_lock_bh(&ar_sdio->lock);
> +
> + if (list_empty(&ar_sdio->bus_req_freeq)) {
> + spin_unlock_bh(&ar_sdio->lock);
> + return NULL;
> + }
> +
> + bus_req =3D list_first_entry(&ar_sdio->bus_req_freeq,
> + struct ath10k_sdio_bus_request, list);
> + list_del(&bus_req->list);
> +
> + spin_unlock_bh(&ar_sdio->lock);
> +
> + return bus_req;
> +}
> +
> +static void ath10k_sdio_free_bus_req(struct ath10k_sdio *ar_sdio,
> + struct ath10k_sdio_bus_request *bus_req)
> +{
> + spin_lock_bh(&ar_sdio->lock);
> + list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq);
> + spin_unlock_bh(&ar_sdio->lock);
> +}
> +
> +static int ath10k_sdio_read_write_sync(struct ath10k *ar, u32 addr, u8 *=
buf,
> + u32 len, u32 request)
> +{
> + struct ath10k_sdio *ar_sdio =3D ath10k_sdio_priv(ar);
> + u8 *tbuf =3D NULL;
Extra space after u8?
> + int ret;
> + bool bounced =3D false;
> +
> + if (request & HIF_BLOCK_BASIS)
> + len =3D round_down(len, ar_sdio->mbox_info.block_size);
> +
> + if (buf_needs_bounce(buf)) {
> + if (!ar_sdio->dma_buffer)
> + return -ENOMEM;
> + /* FIXME: I am not sure if it is always correct to assume
> + * that the SDIO irq is a "fake" irq and sleep is possible.
> + * (this function will get called from
> + * ath10k_sdio_irq_handler
> + */
> + mutex_lock(&ar_sdio->dma_buffer_mutex);
> + tbuf =3D ar_sdio->dma_buffer;
> +
> + if (request & HIF_WRITE)
> + memcpy(tbuf, buf, len);
> +
> + bounced =3D true;
> + } else {
> + tbuf =3D buf;
> + }
So I really hate that ar_sdio->dma_buffer, do we really need it? What if
we just get rid of it and allocate struct sk_buff and pass that around?
No need to do extra copying then, I hope :)
> +
> + ret =3D ath10k_sdio_io(ar_sdio, request, addr, tbuf, len);
> + if ((request & HIF_READ) && bounced)
> + memcpy(buf, tbuf, len);
> +
> + if (bounced)
> + mutex_unlock(&ar_sdio->dma_buffer_mutex);
> +
> + return ret;
> +}
> +
> +static void __ath10k_sdio_write_async(struct ath10k_sdio *ar_sdio,
> + struct ath10k_sdio_bus_request *req)
> +{
> + int status;
> + struct ath10k_htc_ep *ep;
> + struct sk_buff *skb;
> +
> + skb =3D req->skb;
> + status =3D ath10k_sdio_read_write_sync(ar_sdio->ar, req->address,
> + skb->data, req->len,
> + req->request);
> + ep =3D &ar_sdio->ar->htc.endpoint[req->eid];
> + ath10k_htc_notify_tx_completion(ep, skb);
> + ath10k_sdio_free_bus_req(ar_sdio, req);
> +}
> +
> +static void ath10k_sdio_write_async_work(struct work_struct *work)
> +{
> + struct ath10k_sdio *ar_sdio;
> + struct ath10k_sdio_bus_request *req, *tmp_req;
> +
> + ar_sdio =3D container_of(work, struct ath10k_sdio, wr_async_work);
> +
> + spin_lock_bh(&ar_sdio->wr_async_lock);
> + list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) {
> + list_del(&req->list);
> + spin_unlock_bh(&ar_sdio->wr_async_lock);
> + __ath10k_sdio_write_async(ar_sdio, req);
> + spin_lock_bh(&ar_sdio->wr_async_lock);
> + }
> + spin_unlock_bh(&ar_sdio->wr_async_lock);
> +}
> +
> +static void ath10k_sdio_irq_handler(struct sdio_func *func)
> +{
> + int status =3D 0;
> + unsigned long timeout;
> + struct ath10k_sdio *ar_sdio;
> + bool done =3D false;
> +
> + ar_sdio =3D sdio_get_drvdata(func);
> + atomic_set(&ar_sdio->irq_handling, 1);
> +
> + /* Release the host during interrupts so we can pick it back up when
> + * we process commands.
> + */
> + sdio_release_host(ar_sdio->func);
> +
> + timeout =3D jiffies + ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ;
> + while (time_before(jiffies, timeout) && !done) {
> + status =3D ath10k_sdio_mbox_proc_pending_irqs(ar_sdio, &done);
> + if (status)
> + break;
> + }
> +
> + sdio_claim_host(ar_sdio->func);
> +
> + atomic_set(&ar_sdio->irq_handling, 0);
> + wake_up(&ar_sdio->irq_wq);
> +
> + WARN_ON(status && status !=3D -ECANCELED);
> +}
Questionable use of an atomic variable again, looks like badly implement
poor man's locking to me. And instead of wake_up() we should workqueues
or threaded irqs (if sdio supports that).
> +
> +static int ath10k_sdio_hif_disable_intrs(struct ath10k_sdio *ar_sdio)
> +{
> + int ret;
> + struct ath10k_sdio_irq_enable_reg regs;
> + struct ath10k_sdio_irq_data *irq_data =3D &ar_sdio->irq_data;
> +
> + memset(®s, 0, sizeof(regs));
> +
> + ret =3D ath10k_sdio_read_write_sync(ar_sdio->ar,
> + MBOX_INT_STATUS_ENABLE_ADDRESS,
> + ®s.int_status_en, sizeof(regs),
> + HIF_WR_SYNC_BYTE_INC);
> + if (ret) {
> + ath10k_err(ar_sdio->ar, "Unable to disable sdio interrupts\n");
> + return ret;
> + }
> +
> + spin_lock_bh(&irq_data->lock);
> + irq_data->irq_en_reg =3D regs;
> + spin_unlock_bh(&irq_data->lock);
> +
> + return 0;
> +}
> +
> +static int ath10k_sdio_hif_power_up(struct ath10k *ar)
> +{
> + struct ath10k_sdio *ar_sdio =3D ath10k_sdio_priv(ar);
> + struct sdio_func *func =3D ar_sdio->func;
> + int ret =3D 0;
> +
> + if (!ar_sdio->is_disabled)
> + return 0;
> +
> + ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio power on\n");
> +
> + sdio_claim_host(func);
> +
> + ret =3D sdio_enable_func(func);
> + if (ret) {
> + ath10k_err(ar, "Unable to enable sdio func: %d)\n", ret);
> + sdio_release_host(func);
> + return ret;
> + }
> +
> + sdio_release_host(func);
> +
> + /* Wait for hardware to initialise. It should take a lot less than
> + * 20 ms but let's be conservative here.
> + */
> + msleep(20);
> +
> + ar_sdio->is_disabled =3D false;
> +
> + ret =3D ath10k_sdio_hif_disable_intrs(ar_sdio);
> +
> + return ret;
> +}
> +
> +static void ath10k_sdio_hif_power_down(struct ath10k *ar)
> +{
> + struct ath10k_sdio *ar_sdio =3D ath10k_sdio_priv(ar);
> + int ret;
> +
> + if (ar_sdio->is_disabled)
> + return;
> +
> + ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio power off\n");
> +
> + /* Disable the card */
> + sdio_claim_host(ar_sdio->func);
> + ret =3D sdio_disable_func(ar_sdio->func);
> + sdio_release_host(ar_sdio->func);
> +
> + if (ret)
> + ath10k_dbg(ar, ATH10K_DBG_BOOT,
> + "Unable to disable sdio: %d\n", ret);
Shouldn't this be ath10k_warn()?
> +
> + ar_sdio->is_disabled =3D true;
> +}
> +
> +int ath10k_sdio_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
> + struct ath10k_hif_sg_item *items, int n_items)
> +{
> + int i;
> + u32 address;
> + struct ath10k_sdio *ar_sdio =3D ath10k_sdio_priv(ar);
> + struct ath10k_sdio_bus_request *bus_req;
> +
> + bus_req =3D ath10k_sdio_alloc_busreq(ar_sdio);
> +
> + if (WARN_ON_ONCE(!bus_req))
> + return -ENOMEM;
Is ath10k_warn() more approriate?
> + for (i =3D 0; i < n_items; i++) {
> + bus_req->skb =3D items[i].transfer_context;
> + bus_req->request =3D HIF_WRITE;
> + bus_req->eid =3D pipe_id_to_eid(pipe_id);
> + /* Write TX data to the end of the mbox address space */
> + address =3D ar_sdio->mbox_addr[bus_req->eid] +
> + ar_sdio->mbox_size[bus_req->eid] - bus_req->skb->len;
> + bus_req->address =3D address;
> + bus_req->len =3D CALC_TXRX_PADDED_LEN(ar_sdio, bus_req->skb->len);
> +
> + spin_lock_bh(&ar_sdio->wr_async_lock);
> + list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq);
> + spin_unlock_bh(&ar_sdio->wr_async_lock);
> + }
> +
> + queue_work(ar_sdio->workqueue, &ar_sdio->wr_async_work);
> +
> + return 0;
> +}
> +
> +static int ath10k_sdio_hif_enable_intrs(struct ath10k_sdio *ar_sdio)
> +{
> + struct ath10k_sdio_irq_enable_reg regs;
> + int status;
> + struct ath10k_sdio_irq_data *irq_data =3D &ar_sdio->irq_data;
> +
> + memset(®s, 0, sizeof(regs));
> +
> + /* Enable all but CPU interrupts */
> + regs.int_status_en =3D SM(0x01, MBOX_INT_STATUS_ENABLE_ERROR) |
> + SM(0x01, MBOX_INT_STATUS_ENABLE_CPU) |
> + SM(0x01, MBOX_INT_STATUS_ENABLE_COUNTER);
> +
> + /* NOTE: There are some cases where HIF can do detection of
> + * pending mbox messages which is disabled now.
> + */
> + regs.int_status_en |=3D SM(0x01, MBOX_INT_STATUS_ENABLE_MBOX_DATA);
> +
> + /* Set up the CPU Interrupt status Register */
> + regs.cpu_int_status_en =3D 0;
> +
> + /* Set up the Error Interrupt status Register */
> + regs.err_int_status_en =3D
> + SM(0x01, MBOX_ERROR_STATUS_ENABLE_RX_UNDERFLOW) |
> + SM(0x01, MBOX_ERROR_STATUS_ENABLE_TX_OVERFLOW);
> +
> + /* Enable Counter interrupt status register to get fatal errors for
> + * debugging.
> + */
> + regs.cntr_int_status_en =3D SM(ATH10K_SDIO_TARGET_DEBUG_INTR_MASK,
> + MBOX_COUNTER_INT_STATUS_ENABLE_BIT);
> +
> + status =3D ath10k_sdio_read_write_sync(ar_sdio->ar,
> + MBOX_INT_STATUS_ENABLE_ADDRESS,
> + ®s.int_status_en, sizeof(regs),
> + HIF_WR_SYNC_BYTE_INC);
> + if (status) {
> + ath10k_err(ar_sdio->ar,
> + "failed to update interrupt ctl reg err: %d\n",
> + status);
> + return status;
> + }
> +
> + spin_lock_bh(&irq_data->lock);
> + irq_data->irq_en_reg =3D regs;
> + spin_unlock_bh(&irq_data->lock);
> +
> + return 0;
> +}
> +
> +static int ath10k_sdio_hif_start(struct ath10k *ar)
> +{
> + int ret;
> + struct ath10k_sdio *ar_sdio =3D ath10k_sdio_priv(ar);
> + u32 addr, val;
> +
> + addr =3D host_interest_item_address(HI_ITEM(hi_acs_flags));
> +
> + ret =3D ath10k_sdio_hif_diag_read32(ar, addr, &val);
> + if (ret) {
> + ath10k_err(ar, "Unable to read diag mem: %d\n", ret);
> + goto out;
> + }
> +
> + if (val & HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK) {
> + ath10k_dbg(ar, ATH10K_DBG_SDIO,
> + "Mailbox SWAP Service is enabled\n");
> + ar_sdio->swap_mbox =3D true;
> + }
> +
> + /* eid 0 always uses the lower part of the extended mailbox address
> + * space (ext_info[0].htc_ext_addr).
> + */
> + ar_sdio->mbox_addr[0] =3D ar_sdio->mbox_info.ext_info[0].htc_ext_addr;
> + ar_sdio->mbox_size[0] =3D ar_sdio->mbox_info.ext_info[0].htc_ext_sz;
> +
> + sdio_claim_host(ar_sdio->func);
> +
> + /* Register the isr */
> + ret =3D sdio_claim_irq(ar_sdio->func, ath10k_sdio_irq_handler);
> + if (ret) {
> + ath10k_err(ar, "Failed to claim sdio irq: %d\n", ret);
> + sdio_release_host(ar_sdio->func);
> + goto out;
> + }
> +
> + sdio_release_host(ar_sdio->func);
> +
> + ret =3D ath10k_sdio_hif_enable_intrs(ar_sdio);
> + if (ret)
> + ath10k_err(ar, "Failed to enable sdio interrupts: %d\n", ret);
> +
> +out:
> + return ret;
> +}
> +
> +static bool ath10k_sdio_is_on_irq(struct ath10k *ar)
> +{
> + struct ath10k_sdio *ar_sdio =3D ath10k_sdio_priv(ar);
> +
> + return !atomic_read(&ar_sdio->irq_handling);
> +}
Yikes.
> +
> +static void ath10k_sdio_irq_disable(struct ath10k *ar)
> +{
> + struct ath10k_sdio *ar_sdio =3D ath10k_sdio_priv(ar);
> + int ret;
> +
> + sdio_claim_host(ar_sdio->func);
> +
> + atomic_set(&ar_sdio->stopping, 1);
> +
> + if (atomic_read(&ar_sdio->irq_handling)) {
> + sdio_release_host(ar_sdio->func);
> +
> + ret =3D wait_event_interruptible(ar_sdio->irq_wq,
> + ath10k_sdio_is_on_irq(ar));
> + if (ret)
> + return;
> +
> + sdio_claim_host(ar_sdio->func);
> + }
There has to be a better way to implement this, now it feels that it's
just reimplementing the wheel. We should have proper way to wait for
interrupt handlers and workqueues to end etc.
> + ret =3D sdio_release_irq(ar_sdio->func);
> + if (ret)
> + ath10k_err(ar, "Failed to release sdio irq: %d\n", ret);
> +
> + sdio_release_host(ar_sdio->func);
> +}
> +
> +static int ath10k_sdio_config(struct ath10k_sdio *ar_sdio)
> +{
> + struct ath10k *ar =3D ar_sdio->ar;
> + struct sdio_func *func =3D ar_sdio->func;
> + unsigned char byte, asyncintdelay =3D 2;
> + int ret;
> +
> + ath10k_dbg(ar, ATH10K_DBG_BOOT, "SDIO configuration\n");
> +
> + sdio_claim_host(func);
> +
> + byte =3D 0;
> + ret =3D ath10k_sdio_func0_cmd52_rd_byte(func->card,
> + SDIO_CCCR_DRIVE_STRENGTH,
> + &byte);
> +
> + byte =3D (byte & (~(SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT))) |
> + SDIO_DTSx_SET_TYPE_D;
FIELD_PREP(). There are lots of places where that an be used.
> +static void ath10k_sdio_write32(struct ath10k *ar, u32 offset, u32 value=
)
> +{
> +}
> +
> +static u32 ath10k_sdio_read32(struct ath10k *ar, u32 offset)
> +{
> + return 0;
> +}
Somekind of FIXME/TODO comments for write32() and read32()? What
functionality are we going to miss when we don't implement these?
> +static void ath10k_sdio_hif_send_complete_check(struct ath10k *ar,
> + u8 pipe, int force)
> +{
> +}
> +
> +static u16 ath10k_sdio_hif_get_free_queue_number(struct ath10k *ar, u8 p=
ipe)
> +{
> + return 0;
> +}
Similar comments here also.
> +
> +static const struct ath10k_hif_ops ath10k_sdio_hif_ops =3D {
> + .tx_sg =3D ath10k_sdio_hif_tx_sg,
> + .diag_read =3D ath10k_sdio_hif_diag_read,
> + .diag_write =3D ath10k_sdio_diag_write_mem,
> + .exchange_bmi_msg =3D ath10k_sdio_hif_exchange_bmi_msg,
> + .start =3D ath10k_sdio_hif_start,
> + .stop =3D ath10k_sdio_hif_stop,
> + .map_service_to_pipe =3D ath10k_sdio_hif_map_service_to_pipe,
> + .get_default_pipe =3D ath10k_sdio_hif_get_default_pipe,
> + .send_complete_check =3D ath10k_sdio_hif_send_complete_check,
> + .get_free_queue_number =3D ath10k_sdio_hif_get_free_queue_number,
> + .power_up =3D ath10k_sdio_hif_power_up,
> + .power_down =3D ath10k_sdio_hif_power_down,
> + .read32 =3D ath10k_sdio_read32,
> + .write32 =3D ath10k_sdio_write32,
> +#ifdef CONFIG_PM
> + .suspend =3D ath10k_sdio_hif_suspend,
> + .resume =3D ath10k_sdio_hif_resume,
> +#endif
> + .fetch_cal_eeprom =3D ath10k_sdio_hif_fetch_cal_eeprom,
> +};
> +
> +#ifdef CONFIG_PM_SLEEP
> +
> +/* Empty handlers so that mmc subsystem doesn't remove us entirely durin=
g
> + * suspend. We instead follow cfg80211 suspend/resume handlers.
> + */
> +static int ath10k_sdio_pm_suspend(struct device *device)
> +{
> + return 0;
> +}
> +
> +static int ath10k_sdio_pm_resume(struct device *device)
> +{
> + return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(ath10k_sdio_pm_ops, ath10k_sdio_pm_suspend,
> + ath10k_sdio_pm_resume);
> +
> +#define ATH10K_SDIO_PM_OPS (&ath10k_sdio_pm_ops)
> +
> +#else
> +
> +#define ATH10K_SDIO_PM_OPS NULL
> +
> +#endif /* CONFIG_PM_SLEEP */
> +
> +static int ath10k_sdio_probe(struct sdio_func *func,
> + const struct sdio_device_id *id)
> +{
> + int ret;
> + struct ath10k_sdio *ar_sdio;
> + struct ath10k *ar;
> + int i;
> + enum ath10k_hw_rev hw_rev;
> +
> + hw_rev =3D ATH10K_HW_QCA6174;
This needs a comment, at least to remind if ever add something else than
QCA6174 based SDIO design.
> +
> + ar =3D ath10k_core_create(sizeof(*ar_sdio), &func->dev, ATH10K_BUS_SDIO=
,
> + hw_rev, &ath10k_sdio_hif_ops);
> + if (!ar) {
> + dev_err(&func->dev, "failed to allocate core\n");
> + return -ENOMEM;
> + }
> +
> + ath10k_dbg(ar, ATH10K_DBG_BOOT,
> + "sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
> + func->num, func->vendor, func->device,
> + func->max_blksize, func->cur_blksize);
> +
> + ar_sdio =3D ath10k_sdio_priv(ar);
> +
> + ar_sdio->dma_buffer =3D kzalloc(ATH10K_HIF_DMA_BUFFER_SIZE, GFP_KERNEL)=
;
> + if (!ar_sdio->dma_buffer) {
> + ret =3D -ENOMEM;
> + goto err_core_destroy;
> + }
> +
> + ar_sdio->func =3D func;
> + sdio_set_drvdata(func, ar_sdio);
> +
> + ar_sdio->is_disabled =3D true;
> + ar_sdio->ar =3D ar;
> +
> + spin_lock_init(&ar_sdio->lock);
> + spin_lock_init(&ar_sdio->wr_async_lock);
> + spin_lock_init(&ar_sdio->irq_data.lock);
> + mutex_init(&ar_sdio->dma_buffer_mutex);
> +
> + INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
> + INIT_LIST_HEAD(&ar_sdio->wr_asyncq);
> +
> + INIT_WORK(&ar_sdio->wr_async_work, ath10k_sdio_write_async_work);
> + ar_sdio->workqueue =3D create_singlethread_workqueue("ath10k_sdio_wq");
> + if (!ar_sdio->workqueue)
> + goto err;
> +
> + init_waitqueue_head(&ar_sdio->irq_wq);
> +
> + for (i =3D 0; i < ATH10K_SDIO_BUS_REQUEST_MAX_NUM; i++)
> + ath10k_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[i]);
> +
> + ar->dev_id =3D id->device;
> + ar->id.vendor =3D id->vendor;
> + ar->id.device =3D id->device;
> +
> + ath10k_sdio_set_mbox_info(ar_sdio);
> +
> + ret =3D ath10k_sdio_config(ar_sdio);
> + if (ret) {
> + ath10k_err(ar, "Failed to config sdio: %d\n", ret);
> + goto err;
> + }
> +
> + ret =3D ath10k_core_register(ar, 0/*chip_id is not applicaple for SDIO*=
/);
> + if (ret) {
> + ath10k_err(ar, "failed to register driver core: %d\n", ret);
> + goto err;
> + }
I would assume that chip_id is applicaple also with SDIO, there has to
be a register where to get it. Also this kind of comment style is
preferred:
/* TODO: don't know yet how to get chip_id with SDIO */
chip_id =3D 0;
ret =3D ath10k_core_register(ar, chip_id);
> +
> + return ret;
> +
> +err:
> + kfree(ar_sdio->dma_buffer);
> +err_core_destroy:
> + ath10k_core_destroy(ar);
> +
> + return ret;
> +}
> +
> +static void ath10k_sdio_remove(struct sdio_func *func)
> +{
> + struct ath10k_sdio *ar_sdio;
> + struct ath10k *ar;
> +
> + ar_sdio =3D sdio_get_drvdata(func);
> + ar =3D ar_sdio->ar;
> +
> + ath10k_dbg(ar, ATH10K_DBG_BOOT,
> + "sdio removed func %d vendor 0x%x device 0x%x\n",
> + func->num, func->vendor, func->device);
> +
> + (void)ath10k_sdio_hif_disable_intrs(ar_sdio);
> + cancel_work_sync(&ar_sdio->wr_async_work);
> + ath10k_core_unregister(ar);
> + ath10k_core_destroy(ar);
> +
> + kfree(ar_sdio->dma_buffer);
> +}
> +
> +static const struct sdio_device_id ath10k_sdio_devices[] =3D {
> + {SDIO_DEVICE(ATH10K_MANUFACTURER_CODE,
> + (ATH10K_MANUFACTURER_ID_AR6005_BASE | 0xA))},
> + {},
> +};
I suspect there's a more sensible way to create the device table than
this, just no time to check it now. Anyone know?
The naming "ath10k manufacturer" is also wrong, it should be QCA or
Qualcomm.
--=20
Kalle Valo=
^ permalink raw reply
* Re: wl1251 NVS calibration data format
From: Pali Rohár @ 2016-12-16 11:12 UTC (permalink / raw)
To: Gery Kahn, Shahar Lev, Kalle Valo, linux-wireless, linux-kernel,
Sebastian Reichel, Pavel Machek, Ivaylo Dimitrov
In-Reply-To: <201612161201.48356@pali>
[-- Attachment #1: Type: Text/Plain, Size: 1133 bytes --]
Resending email to new Gery's address...
On Friday 16 December 2016 12:01:48 Pali Rohár wrote:
> Hi! Do you know format of wl1251 NVS calibration data file?
>
> I found that there is tool for changing NVS file for wl1271 and newer
> chips (so not for wl1251!) at: https://github.com/gxk/ti-utils
>
> And wl1271 has in NVS data already place for MAC address. And in wlcore
> (for wl1271 and newer) there is really kernel code which is doing
> something with MAC address in NVS, see:
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ti/wlcore/boot.c#n352
Also, there is parsing MAC address from NVS wl1271 data:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ti/wlcore/main.c#n6009
> So... I would like to know if in wl1251 NVS calibration file is also
> some place for MAC address or not.
>
> Default wl1251 NVS calibration file is available in linux-firmware:
> https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/tree/ti-connectivity/wl1251-nvs.bin
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* wl1251 NVS calibration data format
From: Pali Rohár @ 2016-12-16 11:01 UTC (permalink / raw)
To: Gery Kahn, Shahar Lev, Kalle Valo, linux-wireless, linux-kernel,
Sebastian Reichel, Pavel Machek, Ivaylo Dimitrov
[-- Attachment #1: Type: Text/Plain, Size: 831 bytes --]
Hi! Do you know format of wl1251 NVS calibration data file?
I found that there is tool for changing NVS file for wl1271 and newer
chips (so not for wl1251!) at: https://github.com/gxk/ti-utils
And wl1271 has in NVS data already place for MAC address. And in wlcore
(for wl1271 and newer) there is really kernel code which is doing
something with MAC address in NVS, see:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/ti/wlcore/boot.c#n352
So... I would like to know if in wl1251 NVS calibration file is also
some place for MAC address or not.
Default wl1251 NVS calibration file is available in linux-firmware:
https://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/tree/ti-connectivity/wl1251-nvs.bin
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: wl1251 & mac address & calibration data
From: Pali Rohár @ 2016-12-16 10:40 UTC (permalink / raw)
To: Daniel Wagner
Cc: Luis R. Rodriguez, Arend Van Spriel, Tom Gundersen, Johannes Berg,
Ming Lei, Mimi Zohar, Bjorn Andersson, Rafał Miłecki,
Kalle Valo, Sebastian Reichel, Pavel Machek, Michal Kazior,
Ivaylo Dimitrov, Aaro Koskinen, Tony Lindgren, linux-wireless,
Network Development, linux-kernel@vger.kernel.org,
David Woodhouse, Takashi Iwai, Josh Boyer, Dmitry Torokhov
In-Reply-To: <07be7fc8-6c7f-6e03-379d-fa781b248259@monom.org>
[-- Attachment #1: Type: Text/Plain, Size: 2061 bytes --]
On Friday 16 December 2016 08:25:44 Daniel Wagner wrote:
> On 12/16/2016 03:03 AM, Luis R. Rodriguez wrote:
> > For the new API a solution for "fallback mechanisms" should be
> > clean though and I am looking to stay as far as possible from the
> > existing mess. A solution to help both the old API and new API is
> > possible for the "fallback mechanism" though -- but for that I can
> > only refer you at this point to some of Daniel Wagner and Tom
> > Gunderson's firmwared deamon prospect. It should help pave the way
> > for a clean solution and help address other stupid issues.
>
> The firmwared project is hosted here
>
> https://github.com/teg/firmwared
>
> As Luis pointed out, firmwared relies on
> FW_LOADER_USER_HELPER_FALLBACK, which is not enabled by default.
I know. But it does not mean that I cannot enable this option at kernel
compile time.
Bigger problem is that currently request_firmware() first try to load
firmware directly from VFS and after that (if fails) fallback to user
helper.
So I would need to extend kernel firmware code with new function (or
flag) to not use VFS and try only user mode helper.
> I
> don't see any reason why firmwared should not also support loading
> calibration data. If we find a sound way to do this.
It can, but why should I use another daemon for firmware loading as
non-systemd version of udev (and eudev fork) support firmware loading?
I think I stay with udev/eudev.
> As you can see from the commit history it is a pretty young project
> and more ore less reanimation of the old udev firmware loader
> feature. We are getting int into shape, adding integration tests
> etc.
>
> The main motivation for this project is the get movement back in
> stuck discussion on the firmware loader API. Luis was very busy
> writing up all the details on the current situation and purely from
> the amount of documentation need to describe the API you can tell
> something is awry.
>
> Thanks,
> Daniel
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [RFC V3 04/11] nl80211: add driver api for gscan notifications
From: Johannes Berg @ 2016-12-16 10:02 UTC (permalink / raw)
To: Arend Van Spriel; +Cc: linux-wireless
In-Reply-To: <69ec7e9f-cd46-c46d-140c-0b30343cc0f7@broadcom.com>
> Not sure what is meant by "through the buckets".
TBH, I was handwaving because I don't understand this part of gscan
well :-)
> Referring to your
> remark/question in the "Unversal scan proposal" thread:
>
> """
> I'm much more worried about the "bucket reporting" since that doesn't
> fit into the current full BSS reporting model at all. What's your
> suggestion for this?
> """
>
> So this is exactly the dilemma I considered so I decided to stick
> with the full BSS reporting model for gscan as well merely to get it
> discussed so glad you brought it up ;-).
Heh.
Ok, so I missed that. Somehow I thought hidden in the buckets was a
partial reporting :-)
> The problem here is that gscan is a vehicle that serves a number of
> use-cases. So ignoring hotlists, ePNO, etc. the gscan configuration
> still hold several notification types:
>
> - report after completing M scans capturing N best APs or a
> percentage of (M * N).
> - report after completing a scan include a specific bucket.
> - report full scan results.
>
> The first two notification trigger retrieval of gscan results which
> are historic, ie. partial scan results for max M scans.
>
> As said earlier the universal scan proposal has some similarities to
> gscan. Guess you share that as you are using the term "bucket
> reporting" in that discussion ;-). The historic results are needed
> for location (if I am not mistaken) so the full BSS reporting model
> does not fit that. Question is what particular attribute in the
> historic results is needed for location (suspecting only rssi and
> possibly the timestamp, but would like to see that confirmed). I was
> thinking about have historic storage in cfg80211 so we do not need a
> per-driver solution.
Ok, now I'm starting to understand this better, I guess.
As far as I can tell from our code, for cached results we're reporting
the following data:
* some flags
* a scan ID
* and for each AP:
* RSSI
* timestamp
* channel
* BSSID
* SSID (which internally we even have a separate table for and each
AP just has an index to it, to save memory I guess)
* beacon period
* capability field
No IEs and similar things like differentiating probe response/beacon,
so we can't use the full reporting for this.
I have no problem introducing a common storage for this, if necessary
with some fields/nl attributes being optional, but I suspect this is
actually a necessary part of gscan, otherwise you're not able to report
all the necessary data?
johannes
^ permalink raw reply
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