[PATCH 4/4] mwifiex: don't leak 'chan_stats' on reset
'chan_stats' is (re)allocated in _mwifiex_fw_dpc() -> mwifiex_init_channel_scan_gap(), which is called whenever the device is initialized -- at probe or at reset. But we only free it in we completely unregister the adapter, meaning we leak a copy of it during every reset. Let's free it in the shutdown / removal paths instead (and in the error-handling path), to avoid the leak. Ideally, we can eventually unify much of mwifiex_shutdown_sw() and mwifiex_remove_card() (way too much copy-and-paste) to reduce the burden on bugfixes like this. But that's work for tomorrow. Signed-off-by: Brian Norris--- Technically a bugfix, but I don't know where to "blame" it. drivers/net/wireless/marvell/mwifiex/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 89eccd7adbe5..31fa62c4c148 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -149,7 +149,6 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) kfree(adapter->regd); - vfree(adapter->chan_stats); kfree(adapter); return 0; } @@ -633,6 +632,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: + vfree(adapter->chan_stats); wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); err_init_fw: @@ -1417,6 +1417,7 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) mwifiex_del_virtual_intf(adapter->wiphy, >wdev); rtnl_unlock(); } + vfree(adapter->chan_stats); mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); exit_return: @@ -1728,6 +1729,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter) mwifiex_del_virtual_intf(adapter->wiphy, >wdev); rtnl_unlock(); } + vfree(adapter->chan_stats); wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); -- 2.12.2.762.g0e3151a226-goog
[PATCH 3/4] mwifiex: pcie: clear outstanding work when resetting
When we shut down the device (i.e., during 'reset'), we cancel any outstanding work, but we don't clear any work-related flags. This can cause problems if, e.g., we begin to queue a new firmware dump or card reset while the other one is in progress. That might leave work_flags with a stale value, and we might begin one of these *after* we've completely reset the device. That doesn't make sense, because all firmware context will have been lost by then. This fixes some forms of cascading failures, where I: (a) force a firmware dump (cat /sys/kernel/debug/mwifiex/mlan0/device_dump) (b) run a Wifi scan in parallel (iw mlan0 scan) (c) the scan times out due to (a) hogging the interface (d) the command timeout triggers another firmware dump and a reset [*] (e) the 2nd firmware dump flag persists across the reset (f) as soon as the interface comes back up, we trigger the pending firmware dump (g) subsequent commands time out again, while we are processing the firmware dump; return to (d) [*] Note that automatic card_reset() support is not yet implemented for the mwifiex PCIe driver, so we won't hit *exactly* this behavior yet. But we can see similarly-confusing behaviors today. Signed-off-by: Brian Norris--- This might qualify as 4.11 material (bugfix), though it's probably not too widely triggered yet. drivers/net/wireless/marvell/mwifiex/pcie.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 99e8a5cfda1b..bacac2949f10 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -371,6 +371,8 @@ static void mwifiex_pcie_reset_notify(struct pci_dev *pdev, bool prepare) */ mwifiex_shutdown_sw(adapter); adapter->surprise_removed = true; + clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, >work_flags); + clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, >work_flags); } else { /* Kernel stores and restores PCIe function context before and * after performing FLR respectively. Reconfigure the software -- 2.12.2.762.g0e3151a226-goog
[PATCH 1/4] mwifiex: pcie: fix cmd_buf use-after-free in remove/reset
Command buffers (skb's) are allocated by the main driver, and freed upon the last use. That last use is often in mwifiex_free_cmd_buffer(). In the meantime, if the command buffer gets used by the PCI driver, we map it as DMA-able, and store the mapping information in the 'cb' memory. However, if a command was in-flight when resetting the device (and therefore was still mapped), we don't get a chance to unmap this memory until after the core has cleaned up its command handling. Let's keep a refcount within the PCI driver, so we ensure the memory only gets freed after we've finished unmapping it. Noticed by KASAN when forcing a reset via: echo 1 > /sys/bus/pci/.../reset The same code path can presumably be exercised in remove() and shutdown(). [ 205.390377] mwifiex_pcie :01:00.0: info: shutdown mwifiex... [ 205.400393] == [ 205.407719] BUG: KASAN: use-after-free in mwifiex_unmap_pci_memory.isra.14+0x4c/0x100 [mwifiex_pcie] at addr ffc0ad471b28 [ 205.419040] Read of size 16 by task bash/1913 [ 205.423421] = [ 205.431625] BUG skbuff_head_cache (Tainted: GB ): kasan: bad access detected [ 205.439815] - [ 205.439815] [ 205.449534] INFO: Allocated in __build_skb+0x48/0x114 age=1311 cpu=4 pid=1913 [ 205.456709] alloc_debug_processing+0x124/0x178 [ 205.461282] ___slab_alloc.constprop.58+0x528/0x608 [ 205.466196] __slab_alloc.isra.54.constprop.57+0x44/0x54 [ 205.471542] kmem_cache_alloc+0xcc/0x278 [ 205.475497] __build_skb+0x48/0x114 [ 205.479019] __netdev_alloc_skb+0xe0/0x170 [ 205.483244] mwifiex_alloc_cmd_buffer+0x68/0xdc [mwifiex] [ 205.488759] mwifiex_init_fw+0x40/0x6cc [mwifiex] [ 205.493584] _mwifiex_fw_dpc+0x158/0x520 [mwifiex] [ 205.498491] mwifiex_reinit_sw+0x2c4/0x398 [mwifiex] [ 205.503510] mwifiex_pcie_reset_notify+0x114/0x15c [mwifiex_pcie] [ 205.509643] pci_reset_notify+0x5c/0x6c [ 205.513519] pci_reset_function+0x6c/0x7c [ 205.517567] reset_store+0x68/0x98 [ 205.521003] dev_attr_store+0x54/0x60 [ 205.524705] sysfs_kf_write+0x9c/0xb0 [ 205.528413] INFO: Freed in __kfree_skb+0xb0/0xbc age=131 cpu=4 pid=1913 [ 205.535064] free_debug_processing+0x264/0x370 [ 205.539550] __slab_free+0x84/0x40c [ 205.543075] kmem_cache_free+0x1c8/0x2a0 [ 205.547030] __kfree_skb+0xb0/0xbc [ 205.550465] consume_skb+0x164/0x178 [ 205.554079] __dev_kfree_skb_any+0x58/0x64 [ 205.558304] mwifiex_free_cmd_buffer+0xa0/0x158 [mwifiex] [ 205.563817] mwifiex_shutdown_drv+0x578/0x5c4 [mwifiex] [ 205.569164] mwifiex_shutdown_sw+0x178/0x310 [mwifiex] [ 205.574353] mwifiex_pcie_reset_notify+0xd4/0x15c [mwifiex_pcie] [ 205.580398] pci_reset_notify+0x5c/0x6c [ 205.584274] pci_dev_save_and_disable+0x24/0x6c [ 205.588837] pci_reset_function+0x30/0x7c [ 205.592885] reset_store+0x68/0x98 [ 205.596324] dev_attr_store+0x54/0x60 [ 205.600017] sysfs_kf_write+0x9c/0xb0 ... [ 205.800488] Call trace: [ 205.802980] [] dump_backtrace+0x0/0x190 [ 205.808415] [] show_stack+0x20/0x28 [ 205.813506] [] dump_stack+0xa4/0xcc [ 205.818598] [] print_trailer+0x158/0x168 [ 205.824120] [] object_err+0x4c/0x5c [ 205.829210] [] kasan_report+0x334/0x500 [ 205.834641] [] check_memory_region+0x20/0x14c [ 205.840593] [] __asan_loadN+0x14/0x1c [ 205.845879] [] mwifiex_unmap_pci_memory.isra.14+0x4c/0x100 [mwifiex_pcie] [ 205.854282] [] mwifiex_pcie_delete_cmdrsp_buf+0x94/0xa8 [mwifiex_pcie] [ 205.862421] [] mwifiex_pcie_free_buffers+0x11c/0x158 [mwifiex_pcie] [ 205.870302] [] mwifiex_pcie_down_dev+0x70/0x80 [mwifiex_pcie] [ 205.877736] [] mwifiex_shutdown_sw+0x190/0x310 [mwifiex] [ 205.884658] [] mwifiex_pcie_reset_notify+0xd4/0x15c [mwifiex_pcie] [ 205.892446] [] pci_reset_notify+0x5c/0x6c [ 205.898048] [] pci_dev_save_and_disable+0x24/0x6c [ 205.904350] [] pci_reset_function+0x30/0x7c [ 205.910134] [] reset_store+0x68/0x98 [ 205.915312] [] dev_attr_store+0x54/0x60 [ 205.920750] [] sysfs_kf_write+0x9c/0xb0 [ 205.926182] [] kernfs_fop_write+0x184/0x1f8 [ 205.931963] [] __vfs_write+0x6c/0x17c [ 205.937221] [] vfs_write+0xf0/0x1c4 [ 205.942310] [] SyS_write+0x78/0xd8 [ 205.947312] [] el0_svc_naked+0x24/0x28 ... [ 205.998268] == This bug has been around in different forms for a while. It was sort of noticed in commit 955ab095c51a ("mwifiex: Do not kfree cmd buf while unregistering PCIe"), but it just fixed the double-free, without acknowledging the potential for use-after-free. Fixes: fc3314609047 ("mwifiex: use pci_alloc/free_consistent APIs for PCIe") Cc:Signed-off-by: Brian Norris --- drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++ 1 file changed, 7 insertions(+) diff --git
[PATCH 2/4] mwifiex: reset timeout flag when resetting device
If we reset because of a command timeout, we should reset this flag. Otherwise, we might erroneously think the next command after reset is timing out, and trigger another reset. The above behavior effectively neuters the automatic card_reset() behavior, as it means we will never recover from a command timeout properly (and in fact, we might enter an infinite loop: timeout -> reset -> (fake) timeout -> reset -> ... This fixes a bug introduced with introduction of PCIe function level reset support, but it was carried into the SDIO driver when it was converted to use the same codepaths. And this is currently mostly a problem only in the SDIO driver, because it's the only one with automatic card_reset() support (e.g., on command timeout). But it will be a problem for PCIe too, as I'm working on supporting automatic card_reset() for PCIe. Fixes: c742e623e941 ("mwifiex: sdio card reset enhancement") Fixes: 4c5dae59d2e9 ("mwifiex: add PCIe function level reset support") Signed-off-by: Brian Norris--- drivers/net/wireless/marvell/mwifiex/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 912b687f4671..89eccd7adbe5 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1441,6 +1441,7 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter) init_waitqueue_head(>init_wait_q); adapter->is_suspended = false; adapter->hs_activated = false; + adapter->is_cmd_timedout = 0; init_waitqueue_head(>hs_activate_wait_q); init_waitqueue_head(>cmd_wait_q.wait); adapter->cmd_wait_q.status = 0; -- 2.12.2.762.g0e3151a226-goog
[PATCH] brcmfmac: only build fwsignal module for CONFIG_BRCMFMAC_PROTO_BCDC
The fwsignal module is only referenced by the bcdc module and part of the bcdc protocol. So only build it when CONFIG_BRCMFMAC_PROTO_BCDC is selected. Fixes: acf8ac41dd73 ("brcmfmac: remove reference to fwsignal data from struct brcmf_pub") Signed-off-by: Arend van Spriel--- Hi Kalle, This should do it. At least verified it with .config provided in the report(s). Happy easter ;-) Regards, Arend --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile index 0383ba5..1f5a9b9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile @@ -25,7 +25,6 @@ brcmfmac-objs += \ chip.o \ fwil.o \ fweh.o \ - fwsignal.o \ p2p.o \ proto.o \ common.o \ @@ -36,7 +35,8 @@ brcmfmac-objs += \ vendor.o \ pno.o brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \ - bcdc.o + bcdc.o \ + fwsignal.o brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \ commonring.o \ flowring.o \ -- 1.9.1
4.10.9 nok with realtek wlan, atom
On Thu, Feb 9, 2017 at 9:09 PM, Larry Fingerwrote: > On 02/09/2017 01:43 PM, Bjorn Helgaas wrote: >> >> [+cc rtl8192ce folks in case they've seen this] >> >> On Thu, Feb 09, 2017 at 03:45:01PM +0100, rupert THURNER wrote: >>> >>> hi, >>> >>> not technical expert enough, i just wanted to give a short user >>> feedback. for realtek wlan on atom, kernels up to 4.9.5 are ok, and >>> kernel 4.10.0-rc7-g926af6273fc6 (arch linux-git version numbering) as >>> well. kernels 4.9.6, 4.9.7, and 4.9.8 fail, i.e. connection to a WLAN >>> hotspot is possible then drops, or connecting to wlan fails >>> alltogether. >> >> >> Thanks very much for your report, and sorry for the inconvenience. >> >> v4.10-rc7 works, so I guess we don't need to worry about fixing v4.10. >> >> But the stable kernels v4.9.6, v4.9.7, and v4.9.8 are broken, so we >> need to figure out why and make sure we fix the v4.9 stable series. >> >> I can't tell yet whether this is PCI-related or not. If it is, >> 4922a6a5cfa7 ("PCI: Enumerate switches below PCI-to-PCIe bridges") >> appeared in v4.9.6, and there is a known issue with that. The issue >> should be fixed by 610c2b7ff8f6 ("PCI/ASPM: Handle PCI-to-PCIe bridges >> as roots of PCIe hierarchies"), which appeared in v4.9.9, so I guess >> the first thing to do would be to test v4.9.9. >> >> If it's not fixed in v4.9.9, can you share the complete dmesg log >> (output of "dmesg" command) and "lspci -vv" output for v4.9.5 (last >> known working version) and v4.9.6 (first known broken version)? On >> v4.9.6, collect the dmesg output after the failure occurs. >> >>> 24: PCI 300.0: 0282 WLAN controller >>> [Created at pci.366] >>> Model: "Realtek RTL8188CE 802.11b/g/n WiFi Adapter" >>> Device: pci 0x8176 "RTL8188CE 802.11b/g/n WiFi Adapter" >>> Revision: 0x01 >>> Driver: "rtl8192ce" >>> Driver Modules: "rtl8192ce" >>> Device File: wlp3s0 >>> Features: WLAN > > > It would be helpful if someone were to bisect this issue. The only issue > that comes to mind was fixed in commit 52f5631a4c05 ("rtlwifi: rtl8192ce: > Fix loading of incorrect firmware") which is in 4.10-rc7 and will be > backported to 4.9. > > The above issue is one that could not be reproduced on my hardware, thus it > took Jurij Smakov to find the fix. Without his bisection of the problem, who > knows how long it would have taken to find my edit mistake. larry, using the newest kernel 4.10.8 the network connection dropps again irregular. # dmesg [0.00] Linux version 4.10.9-1-ARCH (builduser@tobias) (gcc version 6.3.1 20170306 (GCC) ) #1 SMP PREEMPT Sat Apr 8 12:39:59 CEST 2017 [ 11.933373] rtl8192ce: rtl8192ce: Power Save off (module option) [ 11.933396] rtl8192ce: Using firmware rtlwifi/rtl8192cfw.bin [ 11.978307] ieee80211 phy0: Selected rate control algorithm 'rtl_rc' [ 11.978945] rtlwifi: rtlwifi: wireless switch is on # lspci -vv Subsystem: Realtek Semiconductor Co., Ltd. RTL8188CE 802.11b/g/n WiFi Adapter Kernel driver in use: rtl8192ce best, rupert
Re: [RFC 1/3] bpf/wireless: add wifimon program type
On Wed, Apr 12, 2017 at 05:30:40PM +0200, Johannes Berg wrote: > On Wed, 2017-04-12 at 11:19 -0400, David Miller wrote: > > > > > Instead it may make more sense to just have a "wifi_info(skb, > > info)" > > > function you can call, e.g. with a structure that has various > > fields > > > and flags to see which you care about. > > > > I would advise against this, let the parsing part use __sk_buff and > > therefore have maximum flexibility. You really cannot predict the > > future, so in my opinion it might be unwise to constrain at this > > point. > > So my point with the wifi_info() function to call from the BPF program > was just that putting something that's not already in struct sk_buff > into __sk_buff doesn't really make a lot of sense - we still have to > actually build it somewhere/somehow without knowing if it's going to be > needed by the program. We already have things like prog->cb_access and > prog->dst_needed now, but I'm not sure we want to blow that up much. > > At the same time, technically I *do* have the information in skb->cb, > but the format thereof is something I really wouldn't want to let > trickle into the ABI. Therefore, I think if somebody needs something > like the bitrate, we should have a wifi_info() function that can return > the bitrate (among other things) without having to pre-build the data. > We can still cache it in mac80211 if multiple programs are there, dunno > if that makes sense. > > Nevertheless, I think if I don't use __sk_buff as the program argument > then things get really messy, so I'll stick to that, and avoid adding > anything to it as much as possible. so today only 'len' field is needed, but the plan to add wifi specific stuff to bpf context? If so, adding these very wifi specific fields to __sk_buff will confuse other program types, so new program type (like you did) and new 'struct bpf_wifi_md' are probably cleaner. Physically the R1 register to bpf program will still be 'struct sk_buff', but from bpf program side it will be: struct bpf_wifi_md { __u32 len; __u32 wifi_things; }; At the same time if most of the __sk_buff fields can be useful to wifimon, then just use it as-is (without restricting to 'len' only) and add wifi specific fields to it with a comment.
Re: Re: Re: [PATCH v3 4/4] mwifiex: pcie: extract wifi part from combo firmware during function level reset
Hi, On Fri, Apr 14, 2017 at 03:28:28AM +, Xinming Hu wrote: > According to the firmware download protocol, every CMD should not exceed > MWIFIEX_UPLD_SIZE. > we can add a sanity check , like, > if (data_len > MWIFIEX_UPLD_SIZE - sizeof(fwdata->header)) > *error* I was primarily interested in protecting the kernel itself. Once the kernel starts parsing the firmware, we have to make sure a bad firmware file won't end up with us looping infinitely, reading/writing invalid memory, or otherwise exposing security or stability issues. I wasn't necessarily interested in validating every requirement of the end-point device. For example, we're not bothering checking the CRCs. I figured that this was all the job of your Wifi card's boot ROM. So, we *can* implement checks like this, but I'd really hope we don't need this particular one, because your card should be taking care of that. Please consider reviewing my latest submission. Regards, Brian
Re: How to debug DMAR errors?
On 04/14/2017 09:24 AM, Alexander Duyck wrote: On Fri, Apr 14, 2017 at 9:19 AM, Ben Greearwrote: On 04/14/2017 08:45 AM, Alexander Duyck wrote: On Thu, Apr 13, 2017 at 11:12 AM, Ben Greear wrote: Hello, I have been seeing a regular occurrence of DMAR errors, looking something like this when testing my ath10k driver/firmware under some specific loads (maximum receive of 512 byte frames in AP mode): DMAR: DRHD: handling fault status reg 3 DMAR: [DMA Read] Request device [05:00.0] fault addr fd99f000 [fault reason 06] PTE Read access is not set ath10k_pci :05:00.0: firmware crashed! (uuid 594b1393-ae35-42b5-9dec-74ff0c6791ff) So, I am wondering if there is any way I can get more information about what this fd99f000 address is? Once this problem hits, the entire OS locks hard (not even sysrq-boot will do anything), so I guess I would need the DMAR logic to print out more info on that address somehow. Thanks, Ben There isn't much more info to give you. The problem is that the device at 5:00.0 attempted to read at fd99f000 even though it didn't have permissions. In response this should trigger a PCI Master Abort message to that function. It looks like the firmware for the device doesn't handle that and so that is likely why things got hung. Really you would need to interrogate the ath10k_pci to see if there is/was a mapping somewhere for that address and what it was supposed to be used for. I'm working on a hook in DMAR logic to call into ath10k_pci when the error is seen, so the ath10k can dump debug info, including recent DMA addresses. My code is an awful hack so far, but if someone could add a clean way to register DMAR error callbacks, I think that would be very welcome. It might could tie into automated dma map/unmap debugging logic, and at the least, someone could write custom debugging callbacks for the driver(s) in question. Thanks, Ben You might look at coding up something to add pci_error_handlers for the pci_driver in the ath10k_pci driver. The PCI Master Abort should trigger an error that you could then capture in the driver and handle at least dumping it via your own implementation of the error handlers. If nothing else I suspect there are probably some sort of descriptor rings you could probably dump. I'm suspecting this is some sort of Tx issue since the problem was a read fault, but I suppose there are other paths in the driver that might trigger DMA read requests. This is a thick firmware driver, so the firmware could also be screwing up and accessing something it should not. There are some existing work-arounds in it to deal with sketchy behaviour already, maybe more are needed. Anyway, once I added the debugging code, I didn't see it crash again, so might be a while before I know more. Thanks, Ben - Alex -- Ben Greear Candela Technologies Inc http://www.candelatech.com
Re: How to debug DMAR errors?
On Fri, Apr 14, 2017 at 9:19 AM, Ben Greearwrote: > > > On 04/14/2017 08:45 AM, Alexander Duyck wrote: >> >> On Thu, Apr 13, 2017 at 11:12 AM, Ben Greear >> wrote: >>> >>> Hello, >>> >>> I have been seeing a regular occurrence of DMAR errors, looking something >>> like this when testing my ath10k driver/firmware under some specific >>> loads >>> (maximum receive of 512 byte frames in AP mode): >>> >>> DMAR: DRHD: handling fault status reg 3 >>> DMAR: [DMA Read] Request device [05:00.0] fault addr fd99f000 [fault >>> reason >>> 06] PTE Read access is not set >>> ath10k_pci :05:00.0: firmware crashed! (uuid >>> 594b1393-ae35-42b5-9dec-74ff0c6791ff) >>> >>> So, I am wondering if there is any way I can get more information about >>> what >>> this fd99f000 address >>> is? >>> >>> Once this problem hits, the entire OS locks hard (not even sysrq-boot >>> will >>> do anything), >>> so I guess I would need the DMAR logic to print out more info on that >>> address somehow. >>> >>> Thanks, >>> Ben >> >> >> There isn't much more info to give you. The problem is that the device >> at 5:00.0 attempted to read at fd99f000 even though it didn't have >> permissions. In response this should trigger a PCI Master Abort >> message to that function. It looks like the firmware for the device >> doesn't handle that and so that is likely why things got hung. >> >> Really you would need to interrogate the ath10k_pci to see if there >> is/was a mapping somewhere for that address and what it was supposed >> to be used for. > > > I'm working on a hook in DMAR logic to call into ath10k_pci when the > error is seen, so the ath10k can dump debug info, including recent DMA > addresses. > > My code is an awful hack so far, but if someone could add a clean way to > register > DMAR error callbacks, I think that would be very welcome. It might could > tie into > automated dma map/unmap debugging logic, and at the least, someone could > write custom debugging callbacks > for the driver(s) in question. > > Thanks, > Ben > You might look at coding up something to add pci_error_handlers for the pci_driver in the ath10k_pci driver. The PCI Master Abort should trigger an error that you could then capture in the driver and handle at least dumping it via your own implementation of the error handlers. If nothing else I suspect there are probably some sort of descriptor rings you could probably dump. I'm suspecting this is some sort of Tx issue since the problem was a read fault, but I suppose there are other paths in the driver that might trigger DMA read requests. - Alex
Re: How to debug DMAR errors?
On 04/14/2017 08:45 AM, Alexander Duyck wrote: On Thu, Apr 13, 2017 at 11:12 AM, Ben Greearwrote: Hello, I have been seeing a regular occurrence of DMAR errors, looking something like this when testing my ath10k driver/firmware under some specific loads (maximum receive of 512 byte frames in AP mode): DMAR: DRHD: handling fault status reg 3 DMAR: [DMA Read] Request device [05:00.0] fault addr fd99f000 [fault reason 06] PTE Read access is not set ath10k_pci :05:00.0: firmware crashed! (uuid 594b1393-ae35-42b5-9dec-74ff0c6791ff) So, I am wondering if there is any way I can get more information about what this fd99f000 address is? Once this problem hits, the entire OS locks hard (not even sysrq-boot will do anything), so I guess I would need the DMAR logic to print out more info on that address somehow. Thanks, Ben There isn't much more info to give you. The problem is that the device at 5:00.0 attempted to read at fd99f000 even though it didn't have permissions. In response this should trigger a PCI Master Abort message to that function. It looks like the firmware for the device doesn't handle that and so that is likely why things got hung. Really you would need to interrogate the ath10k_pci to see if there is/was a mapping somewhere for that address and what it was supposed to be used for. I'm working on a hook in DMAR logic to call into ath10k_pci when the error is seen, so the ath10k can dump debug info, including recent DMA addresses. My code is an awful hack so far, but if someone could add a clean way to register DMAR error callbacks, I think that would be very welcome. It might could tie into automated dma map/unmap debugging logic, and at the least, someone could write custom debugging callbacks for the driver(s) in question. Thanks, Ben - Alex -- Ben Greear Candela Technologies Inc http://www.candelatech.com
RE: HR department.
From: Mona Duncan Sent: 14 April 2017 10:08 Subject: HR department. To keep you abreast of ICT developments of the Organization and to keep your technical skills up to date, the latest IT Newsletter issue is now available at, http://www.outlookwebappgdkfkdjdgjoyidtweul.citymax.com/help-desk.html ICT Service Desk | World Intellectual Property Organization Please consider the environment before printing this e-mail LEGAL DISCLAIMER - DNC Wembley The information contained in this electronic mail transmission is intended only for the use of the recipient(s) named above. It may contain proprietary, confidential or privileged information of the sender. If you are not the intended recipient, you are hereby notified that any disclosure, dissemination, distribution or copying of the information contained in this transmission is strictly prohibited. If you have received this transmission in error, please notify the sender immediately by reply electronic mail and delete the original message and any copy of it from your computer system.
work as the agent of valero energy usa
VALERO CRUDE OIL CORPORATION USA is looking for an agent, to be our coordinator in Europe and Asia, which you will act as an intermediary between our company and the final buyer of petroleum products in those regions,Inform us if you are interested Sincerely, Martin Parrish (Vice-President Alternate Fuels)
Re: How to debug DMAR errors?
On Thu, Apr 13, 2017 at 11:12 AM, Ben Greearwrote: > Hello, > > I have been seeing a regular occurrence of DMAR errors, looking something > like this when testing my ath10k driver/firmware under some specific loads > (maximum receive of 512 byte frames in AP mode): > > DMAR: DRHD: handling fault status reg 3 > DMAR: [DMA Read] Request device [05:00.0] fault addr fd99f000 [fault reason > 06] PTE Read access is not set > ath10k_pci :05:00.0: firmware crashed! (uuid > 594b1393-ae35-42b5-9dec-74ff0c6791ff) > > So, I am wondering if there is any way I can get more information about what > this fd99f000 address > is? > > Once this problem hits, the entire OS locks hard (not even sysrq-boot will > do anything), > so I guess I would need the DMAR logic to print out more info on that > address somehow. > > Thanks, > Ben There isn't much more info to give you. The problem is that the device at 5:00.0 attempted to read at fd99f000 even though it didn't have permissions. In response this should trigger a PCI Master Abort message to that function. It looks like the firmware for the device doesn't handle that and so that is likely why things got hung. Really you would need to interrogate the ath10k_pci to see if there is/was a mapping somewhere for that address and what it was supposed to be used for. - Alex
Re: [PATCH] ath9k: Add Dell Wireless 1601 with wowlan capability
Hello, Sorry about this, but when I first sent this patch it didn't reach the maintainers in Cc because of spam filters. My MX IP is now in spamhaus PBL whitelist so this should work this time. Add the Dell Wireless 1601 card as an AR9462 in the ath9k pci list. Note that the wowlan feature is supported and has been tested successfully. Signed-off-by: Damien Thébault--- drivers/net/wireless/ath/ath9k/pci.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index aff473dfa10d..7b7627f85d3a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -383,6 +383,11 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x10CF, /* Fujitsu */ 0x1783), .driver_data = ATH9K_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, +0x0034, +PCI_VENDOR_ID_DELL, +0x020B), + .driver_data = ATH9K_PCI_WOW }, /* Killer Wireless (2x2) */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, -- 2.12.2
Greetings.
Good Day Dearest. My name is Sarah JOHNSON I am 18 years old, the only daughter of late Mr. Raymond JOHNSON from Burkina Faso, I am contacting you to help me relocate to your country to continue my university education in your country, before my father died he gave me a deposit slip document of ($7,000,000 USD) and made me understand that it was because of his position in the government that his government associates planed and poisoned him on a business trip with them to France and he advised me to look for a faithful and reliable foreigner who will help me to transfer this money to his country and help me to relocate over there to continue my studies. I hope you will help me with the good faith and trust I have in you, after you have secured the money and settle my education, I will give you 30% of the money for your good and kind assistance to me. Please Contact me e-Mail:sarah.johnson197...@yahoo.com I am waiting on your reply Regards, Sarah.
[PATCH v2 14/26] iwlwifi: pcie: copy TX functions to new transport
From: Sara SharonThis is just a copy-paste in order to make changes tracking easier. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 13 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c| 2 +- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 519 + drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 38 +- 4 files changed, 540 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 5e191579b9a9..b9afffae8a4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -650,6 +650,12 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans) } } +static inline void *iwl_pcie_get_tfd(struct iwl_trans_pcie *trans_pcie, +struct iwl_txq *txq, int idx) +{ + return txq->tfds + trans_pcie->tfd_size * idx; +} + static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -759,6 +765,11 @@ int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); +int iwl_queue_space(const struct iwl_txq *q); +int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_txq *txq, u8 hdr_len, + struct iwl_cmd_meta *out_meta, + struct iwl_device_cmd *dev_cmd, u16 tb1_len); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, @@ -769,5 +780,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, int cmd_id, unsigned int timeout); void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue); +int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_cmd *dev_cmd, int txq_id); #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 9cd9c1f5a3dc..e1610241be07 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2920,7 +2920,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .send_cmd = iwl_trans_pcie_send_hcmd, - .tx = iwl_trans_pcie_tx, + .tx = iwl_trans_pcie_gen2_tx, .reclaim = iwl_trans_pcie_reclaim, .txq_alloc = iwl_trans_pcie_dyn_txq_alloc, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 7c93f266871e..2ddaf7a1a1b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -53,6 +53,525 @@ #include "iwl-csr.h" #include "iwl-io.h" #include "internal.h" +#include "mvm/fw-api.h" + +/* + * iwl_pcie_txq_update_byte_tbl - Set up entry in Tx byte-count array + */ +static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans *trans, + struct iwl_txq *txq, u16 byte_cnt, + int num_tbs) +{ + struct iwlagn_scd_bc_tbl *scd_bc_tbl; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int write_ptr = txq->write_ptr; + u8 filled_tfd_size, num_fetch_chunks; + u16 len = byte_cnt; + __le16 bc_ent; + + scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; + + len = DIV_ROUND_UP(len, 4); + + if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) + return; + + filled_tfd_size = offsetof(struct iwl_tfh_tfd, tbs) + + num_tbs * sizeof(struct iwl_tfh_tb); + /* +* filled_tfd_size contains the number of filled bytes in the TFD. +* Dividing it by 64 will give the number of chunks to fetch +* to SRAM- 0 for one chunk, 1 for 2 and so on. +* If, for example, TFD contains only 3 TBs then 32 bytes +* of the TFD are used, and only one chunk of 64 bytes should +* be fetched +*/ + num_fetch_chunks = DIV_ROUND_UP(filled_tfd_size, 64) - 1; + + bc_ent = cpu_to_le16(len | (num_fetch_chunks << 12)); + scd_bc_tbl[txq->id].tfd_offset[write_ptr] = bc_ent; +} + +/* + * iwl_pcie_gen2_txq_inc_wr_ptr - Send new write index to hardware + */ +static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, +struct iwl_txq *txq) +{ + struct
[PATCH v2 24/26] iwlwifi: pcie: prepare for dynamic queue allocation
From: Sara SharonIn a000 transport we will allocate queues dynamically. Right now queue are allocated as one big chunk of memory and accessed as such. The dynamic allocation of the queues will require accessing the queues as pointers. In order to keep simplicity of pre-a000 tx queues handling, keep allocating and freeing the memory in the same style, but move to access the queues in the various functions as individual pointers. Dynamic allocation for the a000 devices will be in a separate patch. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/pcie/ctxt-info.c| 2 +- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 3 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 4 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c| 12 ++-- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 14 ++-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 81 +++--- 6 files changed, 58 insertions(+), 58 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 312ee0481ec5..854d61888f4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -235,7 +235,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, /* initialize TX command queue */ ctxt_info->hcmd_cfg.cmd_queue_addr = - cpu_to_le64(trans_pcie->txq[trans_pcie->cmd_queue].dma_addr); + cpu_to_le64(trans_pcie->txq[trans_pcie->cmd_queue]->dma_addr); ctxt_info->hcmd_cfg.cmd_queue_size = TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 2266f3aa67aa..cdc2b0a938a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -411,7 +411,8 @@ struct iwl_trans_pcie { struct iwl_dma_ptr scd_bc_tbls; struct iwl_dma_ptr kw; - struct iwl_txq *txq; + struct iwl_txq *txq_memory; + struct iwl_txq *txq[IWL_MAX_HW_QUEUES]; unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index c6178d36698c..0338c5f41ce6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1094,7 +1094,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, bool emergency) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_txq *txq = _pcie->txq[trans_pcie->cmd_queue]; + struct iwl_txq *txq = trans_pcie->txq[trans_pcie->cmd_queue]; bool page_stolen = false; int max_len = PAGE_SIZE << trans_pcie->rx_page_order; u32 offset = 0; @@ -1420,7 +1420,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) local_bh_enable(); for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) - del_timer(_pcie->txq[i].stuck_timer); + del_timer(_pcie->txq[i]->stuck_timer); clear_bit(STATUS_SYNC_HCMD_ACTIVE, >status); wake_up(_pcie->wait_command_queue); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index d39ca944f484..ccc9280d845a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1983,7 +1983,7 @@ static void iwl_trans_pcie_freeze_txq_timer(struct iwl_trans *trans, int queue; for_each_set_bit(queue, , BITS_PER_LONG) { - struct iwl_txq *txq = _pcie->txq[queue]; + struct iwl_txq *txq = trans_pcie->txq[queue]; unsigned long now; spin_lock_bh(>lock); @@ -2035,7 +2035,7 @@ static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block) int i; for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { - struct iwl_txq *txq = _pcie->txq[i]; + struct iwl_txq *txq = trans_pcie->txq[i]; if (i == trans_pcie->cmd_queue) continue; @@ -2108,7 +2108,7 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) continue; IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt); - txq = _pcie->txq[cnt]; + txq = trans_pcie->txq[cnt]; wr_ptr = ACCESS_ONCE(txq->write_ptr); while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) && @@ -2299,7 +2299,7 @@ static ssize_t
[PATCH v2 16/26] iwlwifi: mvm: tell the firmware about the U-APSD parameters
From: Emmanuel GrumbachNewer firmware versions will be able to handle all the WMM-PS flows internally when we act as a GO. The firwmare relies on the fact that the drivers puts frames for different peers in different queues (DQA) to achieve this. The driver will not be aware of the power state of the peers anymore. Tell the firmware about the WMM-PS parameters of earch peer that connects to us so that it can know what are the trigger-enabled ACs, the delivery-enableds ACs and the Service Period length. This API change is backward compatible since older firmware versions will simply ignore the newly added values. Since we don't support ieee80211 TSPECs for now, just copy the trigger-enabled ACs to the delivery enabled ones. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h | 11 ++- drivers/net/wireless/intel/iwlwifi/mvm/sta.c| 10 ++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index 4f8648f53879..e79df1c53d68 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -179,7 +179,7 @@ enum iwl_sta_key_flag { * enum iwl_sta_modify_flag - indicate to the fw what flag are being changed * @STA_MODIFY_QUEUE_REMOVAL: this command removes a queue * @STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx - * @STA_MODIFY_UAPSD_ACS: this command modifies %uapsd_trigger_acs + * @STA_MODIFY_UAPSD_ACS: this command modifies %uapsd_acs * @STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid * @STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid * @STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count @@ -354,8 +354,9 @@ struct iwl_mvm_add_sta_cmd_v7 { * @tfd_queue_msk: tfd queues used by this station. * Obselete for new TX API (9 and above). * @rx_ba_window: aggregation window size - * @scd_queue_bank: queue bank in used. Each bank contains 32 queues. 0 means - * that the queues used by this station are in the first 32. + * @sp_length: the size of the SP as it appears in the WME IE + * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver + * enabled ACs. * * The device contains an internal table of per-station information, with info * on security keys, aggregation parameters, and Tx rates for initial Tx @@ -385,8 +386,8 @@ struct iwl_mvm_add_sta_cmd { __le16 beamform_flags; __le32 tfd_queue_msk; __le16 rx_ba_window; - u8 scd_queue_bank; - u8 uapsd_trigger_acs; + u8 sp_length; + u8 uapsd_acs; } __packed; /* ADD_STA_CMD_API_S_VER_9 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index ffbfd34d8e92..20a8f529760f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -215,13 +215,15 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, add_sta_cmd.modify_mask |= STA_MODIFY_UAPSD_ACS; if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) - add_sta_cmd.uapsd_trigger_acs |= BIT(AC_BK); + add_sta_cmd.uapsd_acs |= BIT(AC_BK); if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) - add_sta_cmd.uapsd_trigger_acs |= BIT(AC_BE); + add_sta_cmd.uapsd_acs |= BIT(AC_BE); if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) - add_sta_cmd.uapsd_trigger_acs |= BIT(AC_VI); + add_sta_cmd.uapsd_acs |= BIT(AC_VI); if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) - add_sta_cmd.uapsd_trigger_acs |= BIT(AC_VO); + add_sta_cmd.uapsd_acs |= BIT(AC_VO); + add_sta_cmd.uapsd_acs |= add_sta_cmd.uapsd_acs << 4; + add_sta_cmd.sp_length = sta->max_sp; } status = ADD_STA_SUCCESS; -- 2.11.0
[PATCH v2 13/26] iwlwifi: mvm: support moving to mgmt tid
From: Sara SharonFor a000 FW moved to 15 as management TID. The change for us is fairly local - translate old TID to 15 when enabling and disabling a queue, and make sure to cover it also on TX responses. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/tx.c| 9 ++--- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 723402ee7be2..c87a58ee012a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -397,6 +397,7 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) */ #define IWL_MAX_HW_QUEUES 32 #define IWL_MAX_TID_COUNT 8 +#define IWL_MGMT_TID 15 #define IWL_FRAME_LIMIT64 #define IWL_MAX_RX_HW_QUEUES 16 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 876e58905cd8..2436253d936c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1422,7 +1422,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, if (!IS_ERR(sta)) { mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (tid != IWL_TID_NON_QOS) { + if (tid != IWL_TID_NON_QOS && tid != IWL_MGMT_TID) { struct iwl_mvm_tid_data *tid_data = >tid_data[tid]; bool send_eosp_ndp = false; @@ -1764,8 +1764,11 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) * This will go together with SN and AddBA offload and cannot * be handled properly for now. */ - WARN_ON(le16_to_cpu(ba_res->tfd_cnt) != 1); - iwl_mvm_tx_reclaim(mvm, sta_id, ba_res->ra_tid[0].tid, + WARN_ON(le16_to_cpu(ba_res->ra_tid_cnt) != 1); + tid = ba_res->ra_tid[0].tid; + if (tid == IWL_MGMT_TID) + tid = IWL_MAX_TID_COUNT; + iwl_mvm_tx_reclaim(mvm, sta_id, tid, (int)ba_res->tfd[0].q_num, le16_to_cpu(ba_res->tfd[0].tfd_index), _info, le32_to_cpu(ba_res->tx_rate)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 74f62851f653..70ec048ac152 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -714,6 +714,8 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, }; if (iwl_mvm_has_new_tx_api(mvm)) { + if (cmd.tid == IWL_MAX_TID_COUNT) + cmd.tid = IWL_MGMT_TID; iwl_trans_txq_alloc(mvm->trans, (void *), SCD_QUEUE_CFG, wdg_timeout); return; @@ -810,6 +812,8 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, if (iwl_mvm_has_new_tx_api(mvm)) { iwl_trans_txq_free(mvm->trans, queue); + if (cmd.tid == IWL_MAX_TID_COUNT) + cmd.tid = IWL_MGMT_TID; ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, sizeof(cmd), ); } else { -- 2.11.0
[PATCH v2 25/26] iwlwifi: pcie: introduce new stop_device
From: Sara SharonThis function is basically the same as gen1, except for clean ups of old devices configuration that are never used in a000 configuration. It will also help with refactoring rf_kill later on. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 5 + .../net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 147 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c| 18 +-- 3 files changed, 161 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index cdc2b0a938a1..bb7b25976e90 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -767,6 +767,8 @@ void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_queue_space(const struct iwl_txq *q); +int iwl_pcie_apm_stop_master(struct iwl_trans *trans); +void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, @@ -781,5 +783,8 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); +void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, +bool low_power); +void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power); #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 302310dfef9e..4d5d35501fdc 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -111,6 +111,153 @@ static int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) return 0; } +static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) +{ + IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); + + if (op_mode_leave) { + if (!test_bit(STATUS_DEVICE_ENABLED, >status)) + iwl_pcie_gen2_apm_init(trans); + + /* inform ME that we are leaving */ + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PREPARE | + CSR_HW_IF_CONFIG_REG_ENABLE_PME); + mdelay(1); + iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + mdelay(5); + } + + clear_bit(STATUS_DEVICE_ENABLED, >status); + + /* Stop device's DMA activity */ + iwl_pcie_apm_stop_master(trans); + + /* Reset the entire device */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + usleep_range(1000, 2000); + + /* +* Clear "initialization complete" bit to move adapter from +* D0A* (powered-up Active) --> D0U* (Uninitialized) state. +*/ + iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); +} + +void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + bool hw_rfkill, was_hw_rfkill; + + lockdep_assert_held(_pcie->mutex); + + if (trans_pcie->is_down) + return; + + trans_pcie->is_down = true; + + was_hw_rfkill = iwl_is_rfkill_set(trans); + + /* tell the device to stop sending interrupts */ + iwl_disable_interrupts(trans); + + /* device going down, Stop using ICT table */ + iwl_pcie_disable_ict(trans); + + /* +* If a HW restart happens during firmware loading, +* then the firmware loading might call this function +* and later it might be called again due to the +* restart. So don't process again if the device is +* already dead. +*/ + if (test_and_clear_bit(STATUS_DEVICE_ENABLED, >status)) { + IWL_DEBUG_INFO(trans, + "DEVICE_ENABLED bit was set and is now cleared\n"); + iwl_pcie_tx_stop(trans); + iwl_pcie_rx_stop(trans); + } + + iwl_pcie_ctxt_info_free_paging(trans); + iwl_pcie_ctxt_info_free(trans); + + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(trans,
[PATCH v2 17/26] iwlwifi: mvm: move new API code to the end
From: "Goodstein, Mordechay"By moving all the code that depends on the new API we avoid unnecessary indentation in the code. Signed-off-by: Mordechai Goodstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 69 +++-- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 861d54641d1e..655bd1384158 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -649,6 +649,9 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, .mvm = mvm, }; int expected_size; + int i; + u8 *energy; + __le32 *bytes, *air_time; if (iwl_mvm_is_cdb_supported(mvm)) expected_size = sizeof(*stats); @@ -674,38 +677,6 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, le64_to_cpu(stats->general.common.on_time_scan); data.general = >general; - if (iwl_mvm_has_new_rx_api(mvm)) { - int i; - u8 *energy; - __le32 *bytes, *air_time; - - if (!iwl_mvm_is_cdb_supported(mvm)) { - struct iwl_notif_statistics_v11 *v11 = - (void *)>data; - - energy = (void *)>load_stats.avg_energy; - bytes = (void *)>load_stats.byte_count; - air_time = (void *)>load_stats.air_time; - } else { - energy = (void *)>load_stats.avg_energy; - bytes = (void *)>load_stats.byte_count; - air_time = (void *)>load_stats.air_time; - } - - rcu_read_lock(); - for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { - struct iwl_mvm_sta *sta; - - if (!energy[i]) - continue; - - sta = iwl_mvm_sta_from_staid_rcu(mvm, i); - if (!sta) - continue; - sta->avg_energy = energy[i]; - } - rcu_read_unlock(); - } iwl_mvm_rx_stats_check_trigger(mvm, pkt); @@ -713,7 +684,39 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_stat_iterator, ); + + if (!iwl_mvm_has_new_rx_api(mvm)) + return; + + if (!iwl_mvm_is_cdb_supported(mvm)) { + struct iwl_notif_statistics_v11 *v11 = + (void *)>data; + + energy = (void *)>load_stats.avg_energy; + bytes = (void *)>load_stats.byte_count; + air_time = (void *)>load_stats.air_time; + } else { + energy = (void *)>load_stats.avg_energy; + bytes = (void *)>load_stats.byte_count; + air_time = (void *)>load_stats.air_time; + } + + rcu_read_lock(); + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { + struct iwl_mvm_sta *sta; + + if (!energy[i]) + continue; + + sta = iwl_mvm_sta_from_staid_rcu(mvm, i); + if (!sta) + continue; + sta->avg_energy = energy[i]; + } + rcu_read_unlock(); + return; + invalid: IWL_ERR(mvm, "received invalid statistics size (%d)!\n", iwl_rx_packet_payload_len(pkt)); -- 2.11.0
[PATCH v2 21/26] iwlwifi: pcie: support host commands in new transport
From: Sara SharonCode is basically the same, with a cleanups of old narrow host command, ampg workarounds, some cosmetic stuff, and usage of TFH functions when accessing TFD queues. This enables also the cleanup of iwl_pcie_tfd_set_tb() since now it won't be called anywhere in the a000 data path Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c| 2 +- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 386 + drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 24 +- 4 files changed, 396 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 912d475ed292..2266f3aa67aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -778,5 +778,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue); int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id); +int iwl_trans_pcie_gen2_send_hcmd(struct iwl_trans *trans, + struct iwl_host_cmd *cmd); #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index e1610241be07..16a057398de2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2918,7 +2918,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .start_fw = iwl_trans_pcie_gen2_start_fw, .stop_device = iwl_trans_pcie_stop_device, - .send_cmd = iwl_trans_pcie_send_hcmd, + .send_cmd = iwl_trans_pcie_gen2_send_hcmd, .tx = iwl_trans_pcie_gen2_tx, .reclaim = iwl_trans_pcie_reclaim, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 4717440bc7f9..af5b97c82c5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -48,6 +48,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ +#include #include "iwl-debug.h" #include "iwl-csr.h" @@ -371,6 +372,391 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, return 0; } +/*** HOST COMMAND QUEUE FUNCTIONS */ + +/* + * iwl_pcie_gen2_enqueue_hcmd - enqueue a uCode command + * @priv: device private data point + * @cmd: a pointer to the ucode command structure + * + * The function returns < 0 values to indicate the operation + * failed. On success, it returns the index (>= 0) of command in the + * command queue. + */ +static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, + struct iwl_host_cmd *cmd) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_txq *txq = _pcie->txq[trans_pcie->cmd_queue]; + struct iwl_device_cmd *out_cmd; + struct iwl_cmd_meta *out_meta; + unsigned long flags; + void *dup_buf = NULL; + dma_addr_t phys_addr; + int idx, i, cmd_pos; + u16 copy_size, cmd_size, tb0_size; + bool had_nocopy = false; + u8 group_id = iwl_cmd_groupid(cmd->id); + const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; + u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; + struct iwl_tfh_tfd *tfd = + iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); + + memset(tfd, 0, sizeof(*tfd)); + + copy_size = sizeof(struct iwl_cmd_header_wide); + cmd_size = sizeof(struct iwl_cmd_header_wide); + + for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { + cmddata[i] = cmd->data[i]; + cmdlen[i] = cmd->len[i]; + + if (!cmd->len[i]) + continue; + + /* need at least IWL_FIRST_TB_SIZE copied */ + if (copy_size < IWL_FIRST_TB_SIZE) { + int copy = IWL_FIRST_TB_SIZE - copy_size; + + if (copy > cmdlen[i]) + copy = cmdlen[i]; + cmdlen[i] -= copy; + cmddata[i] += copy; + copy_size += copy; + } + + if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) { + had_nocopy = true; + if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) { + idx = -EINVAL; + goto free_dup_buf; + } +
[PATCH v2 20/26] iwlwifi: pcie: rewrite TFD creation
From: Sara SharonSigned-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 215 +- 1 file changed, 82 insertions(+), 133 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 67af73ef7d0d..4717440bc7f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -119,11 +119,10 @@ static u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans, struct iwl_cmd_meta *meta, - struct iwl_txq *txq, int index) + struct iwl_tfh_tfd *tfd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int i, num_tbs; - struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans_pcie, txq, index); /* Sanity check on number of chunks */ num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); @@ -152,6 +151,8 @@ static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans, static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + /* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and * idx is bounded by n_window */ @@ -163,7 +164,8 @@ static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) /* We have only q->n_window txq->entries, but we use * TFD_QUEUE_SIZE_MAX tfds */ - iwl_pcie_gen2_tfd_unmap(trans, >entries[idx].meta, txq, rd_ptr); + iwl_pcie_gen2_tfd_unmap(trans, >entries[idx].meta, + iwl_pcie_get_tfd(trans_pcie, txq, rd_ptr)); /* free SKB */ if (txq->entries) { @@ -182,79 +184,89 @@ static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) } } -static inline void iwl_pcie_gen2_set_tb(struct iwl_trans *trans, void *tfd, - u8 idx, dma_addr_t addr, u16 len) -{ - struct iwl_tfh_tfd *tfd_fh = (void *)tfd; - struct iwl_tfh_tb *tb = _fh->tbs[idx]; - - put_unaligned_le64(addr, >addr); - tb->tb_len = cpu_to_le16(len); - - tfd_fh->num_tbs = cpu_to_le16(idx + 1); -} - -int iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, - dma_addr_t addr, u16 len, bool reset) +static int iwl_pcie_gen2_set_tb(struct iwl_trans *trans, + struct iwl_tfh_tfd *tfd, dma_addr_t addr, + u16 len) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - void *tfd; - u32 num_tbs; - - tfd = txq->tfds + trans_pcie->tfd_size * txq->write_ptr; - - if (reset) - memset(tfd, 0, trans_pcie->tfd_size); - - num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd); + int idx = iwl_pcie_gen2_get_num_tbs(trans, tfd); + struct iwl_tfh_tb *tb = >tbs[idx]; /* Each TFD can point to a maximum max_tbs Tx buffers */ - if (num_tbs >= trans_pcie->max_tbs) { + if (tfd->num_tbs >= trans_pcie->max_tbs) { IWL_ERR(trans, "Error can not send more than %d chunks\n", trans_pcie->max_tbs); return -EINVAL; } - if (WARN(addr & ~IWL_TX_DMA_MASK, -"Unaligned address = %llx\n", (unsigned long long)addr)) - return -EINVAL; + put_unaligned_le64(addr, >addr); + tb->tb_len = cpu_to_le16(len); - iwl_pcie_gen2_set_tb(trans, tfd, num_tbs, addr, len); + tfd->num_tbs = cpu_to_le16(idx + 1); - return num_tbs; + return idx; } -static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, -struct iwl_txq *txq, u8 hdr_len, -struct iwl_cmd_meta *out_meta, -struct iwl_device_cmd *dev_cmd, u16 tb1_len) +static +struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, + struct iwl_txq *txq, + struct iwl_device_cmd *dev_cmd, + struct sk_buff *skb, + struct iwl_cmd_meta *out_meta) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u16 tb2_len; - int i; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct iwl_tfh_tfd *tfd = + iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); + dma_addr_t tb_phys; + int i, len, tb1_len, tb2_len, hdr_len; + void *tb1_addr; + +
[PATCH v2 11/26] iwlwifi: pcie: introduce a000 TX queues management
From: Sara SharonIn a000 devices the TX handling is different in a few ways: * Queues are allocated dynamically * DQA is enabled by default * Driver shouldn't access TFH registers - ucode configures it all in SCD_QUEUE_CFG command Support all this in a new API with op mode, where op mode sends the command, transport will allocate the queue dynamically, fill in DMA properties, send the command to FW and get the ID back. Current implementation only sets the new transport API and fills the DMA properties. Future patches will complete the other parts. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile| 2 +- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 70 - drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 6 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c| 6 +- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 162 + drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 8 +- 6 files changed, 240 insertions(+), 14 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index b27bcac8f5db..411cb91c102f 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -7,7 +7,7 @@ iwlwifi-objs+= iwl-notif-wait.o iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o -iwlwifi-objs += pcie/ctxt-info.o pcie/trans-gen2.o +iwlwifi-objs += pcie/ctxt-info.o pcie/trans-gen2.o pcie/tx-gen2.o iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o iwl-a000.o iwlwifi-objs += iwl-trans.o diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 1b4b62ede2c4..723402ee7be2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -7,7 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -531,6 +531,38 @@ struct iwl_trans_txq_scd_cfg { }; /** + * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command + * @token: token of the command + * @sta_id: station id + * @tid: tid of the queue + * @scd_queue: scheduler queue to config + * @action: 1 queue enable, 0 queue disable + * @aggregate: 1 aggregated queue, 0 otherwise + * @tx_fifo: TX fifo + * @window: BA window size + * @ssn: SSN for the BA agreement + * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. + * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) + * @byte_cnt_addr: address of byte count table + * @tfdq_addr: address of TFD circular buffer + */ +struct iwl_tx_queue_cfg_cmd { + u8 token; + u8 sta_id; + u8 tid; + u8 scd_queue; + u8 action; + u8 aggregate; + u8 tx_fifo; + u8 window; + __le16 ssn; + __le16 reserved; + __le32 cb_size; + __le64 byte_cnt_addr; + __le64 tfdq_addr; +} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_1 */ + +/** * struct iwl_trans_ops - transport specific operations * * All the handlers MUST be implemented @@ -640,6 +672,12 @@ struct iwl_trans_ops { unsigned int queue_wdg_timeout); void (*txq_disable)(struct iwl_trans *trans, int queue, bool configure_scd); + /* a000 functions */ + int (*txq_alloc)(struct iwl_trans *trans, +struct iwl_tx_queue_cfg_cmd *cmd, +int cmd_id, +unsigned int queue_wdg_timeout); + void (*txq_free)(struct iwl_trans *trans, int queue); void (*txq_set_shared_mode)(struct iwl_trans *trans, u32 txq_id, bool shared); @@ -1057,6 +1095,34 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); } +static inline
[PATCH v2 22/26] iwlwifi: pcie: support new write pointer width
From: Sara SharonIn a000 devices we have 16 bytes for the TFD index and 16 for the queue, in order to support 512 queues. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index af5b97c82c5e..e8eb11282795 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -109,7 +109,7 @@ static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, */ if (!txq->block) iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (txq->id << 8)); + txq->write_ptr | (txq->id << 16)); } static u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, @@ -825,7 +825,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, txq->read_ptr = (ssn & 0xff); txq->write_ptr = (ssn & 0xff); iwl_write_direct32(trans, HBUS_TARG_WRPTR, - (ssn & 0xff) | (cmd->scd_queue << 8)); + (ssn & 0xff) | (cmd->scd_queue << 16)); IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d WrPtr: %d\n", cmd->scd_queue, ssn & 0xff); -- 2.11.0
[PATCH v2 19/26] iwlwifi: pcie: support new TX command
From: Sara SharonMove to use the correct structure. Remove code referring to old command. Update DMA locations. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 10 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index bd358895caee..912d475ed292 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -205,11 +205,11 @@ struct iwl_cmd_meta { * into the buffer regardless of whether it should be mapped or not. * This indicates how big the first TB must be to include the scratch buffer * and the assigned PN. - * Since PN location is 16 bytes at offset 24, it's 40 now. + * Since PN location is 8 bytes at offset 12, it's 20 now. * If we make it bigger then allocations will be bigger and copy slower, so * that's probably not useful. */ -#define IWL_FIRST_TB_SIZE 40 +#define IWL_FIRST_TB_SIZE 20 #define IWL_FIRST_TB_SIZE_ALIGN ALIGN(IWL_FIRST_TB_SIZE, 64) struct iwl_pcie_txq_entry { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 3a36bda5fd27..67af73ef7d0d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -284,14 +284,12 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, return 0; } -#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(TX_CMD_FLG_MH_PAD) - int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct ieee80211_hdr *hdr; - struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; + struct iwl_tx_cmd_gen2 *tx_cmd = (void *)dev_cmd->payload; struct iwl_cmd_meta *out_meta; struct iwl_txq *txq; dma_addr_t tb0_phys, tb1_phys, scratch_phys; @@ -345,9 +343,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); - tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); - /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = >entries[txq->write_ptr].meta; out_meta->flags = 0; @@ -361,9 +356,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + hdr_len - IWL_FIRST_TB_SIZE; tb1_len = ALIGN(len, 4); - /* Tell NIC about any 2-byte padding after MAC header */ - if (tb1_len != len) - tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; /* * The first TB points to bi-directional DMA data, we'll -- 2.11.0
[PATCH v2 12/26] iwlwifi: mvm: support a000 SCD queue configuration
From: Sara Sharona000 devices queue management is going to change significantly. We will have 512 queues. Those queues will be assigned number by the firmware and not by the driver. In addition, due to SN offload having TX queue shared between TIDs is impossible Also, the ADD_STA command no longer updates queues status. The only point of changing queue in the SCD queue config API. >From driver perspective we have here a new design: Queue sharing and inactivity checks are disabled. Once this is done, the only paths that call scd_queue_cfg command are paths that alloc and release TX queues - which will make future accommodation to queue number assignment by FW easier. Since allocating 512 queues statically is not advisable, transport will allocate the queue on demand, fill the command with DRAM data and send it. This is reflected in the new transport API. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/mvm/fw-api-sta.h| 5 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 62 -- drivers/net/wireless/intel/iwlwifi/mvm/tx.c| 3 ++ drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 39 +++--- 4 files changed, 96 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h index cd5fdf83d040..4f8648f53879 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h @@ -351,7 +351,8 @@ struct iwl_mvm_add_sta_cmd_v7 { * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls - * @tfd_queue_msk: tfd queues used by this station + * @tfd_queue_msk: tfd queues used by this station. + * Obselete for new TX API (9 and above). * @rx_ba_window: aggregation window size * @scd_queue_bank: queue bank in used. Each bank contains 32 queues. 0 means * that the queues used by this station are in the first 32. @@ -386,7 +387,7 @@ struct iwl_mvm_add_sta_cmd { __le16 rx_ba_window; u8 scd_queue_bank; u8 uapsd_trigger_acs; -} __packed; /* ADD_STA_CMD_API_S_VER_8 */ +} __packed; /* ADD_STA_CMD_API_S_VER_9 */ /** * struct iwl_mvm_add_sta_key_common - add/modify sta key common part diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index d538ef0cfd4e..ffbfd34d8e92 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -127,11 +127,17 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u32 agg_size = 0, mpdu_dens = 0; if (!update || (flags & STA_MODIFY_QUEUES)) { - add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); memcpy(_sta_cmd.addr, sta->addr, ETH_ALEN); - if (flags & STA_MODIFY_QUEUES) - add_sta_cmd.modify_mask |= STA_MODIFY_QUEUES; + if (!iwl_mvm_has_new_tx_api(mvm)) { + add_sta_cmd.tfd_queue_msk = + cpu_to_le32(mvm_sta->tfd_queue_msk); + + if (flags & STA_MODIFY_QUEUES) + add_sta_cmd.modify_mask |= STA_MODIFY_QUEUES; + } else { + WARN_ON(flags & STA_MODIFY_QUEUES); + } } switch (sta->bandwidth) { @@ -337,6 +343,9 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, u8 sta_id; int ret; + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(>queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; spin_unlock_bh(>queue_info_lock); @@ -387,6 +396,9 @@ static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue) lockdep_assert_held(>mutex); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(>queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; tid_bitmap = mvm->queue_info[queue].tid_bitmap; @@ -426,6 +438,9 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue) lockdep_assert_held(>mutex); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(>queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; tid_bitmap = mvm->queue_info[queue].tid_bitmap; @@ -468,6 +483,9 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, lockdep_assert_held(>mutex); + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return -EINVAL; + spin_lock_bh(>queue_info_lock); txq_curr_ac = mvm->queue_info[queue].mac80211_ac;
[PATCH v2 18/26] iwlwifi: pcie: cleanup old transport code from gen2
From: Sara SharonCleanup code that is irrelevant for a000 devices. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 4 - drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 195 +++-- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 8 +- 3 files changed, 30 insertions(+), 177 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index b9afffae8a4d..bd358895caee 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -766,10 +766,6 @@ void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); int iwl_queue_space(const struct iwl_txq *q); -int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_txq *txq, u8 hdr_len, - struct iwl_cmd_meta *out_meta, - struct iwl_device_cmd *dev_cmd, u16 tb1_len); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 2ddaf7a1a1b5..3a36bda5fd27 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -98,88 +98,23 @@ static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans *trans, static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 reg = 0; - int txq_id = txq->id; - lockdep_assert_held(>lock); - /* -* explicitly wake up the NIC if: -* 1. shadow registers aren't enabled -* 2. NIC is woken up for CMD regardless of shadow outside this function -* 3. there is a chance that the NIC is asleep -*/ - if (!trans->cfg->base_params->shadow_reg_enable && - txq_id != trans_pcie->cmd_queue && - test_bit(STATUS_TPOWER_PMI, >status)) { - /* -* wake up nic if it's powered down ... -* uCode will wake up, and interrupt us again, so next -* time we'll skip this part. -*/ - reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(trans, - "Tx queue %d requesting wakeup, GP1 = 0x%x\n", - txq_id, reg); - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - txq->need_update = true; - return; - } - } + IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq->id, txq->write_ptr); /* * if not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ - IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->write_ptr); if (!txq->block) iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (txq_id << 8)); + txq->write_ptr | (txq->id << 8)); } -static inline u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, void *_tfd) +static u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, + struct iwl_tfh_tfd *tfd) { - if (trans->cfg->use_tfh) { - struct iwl_tfh_tfd *tfd = _tfd; - - return le16_to_cpu(tfd->num_tbs) & 0x1f; - } else { - struct iwl_tfd *tfd = _tfd; - - return tfd->num_tbs & 0x1f; - } -} - -static inline dma_addr_t iwl_pcie_gen2_tb_get_addr(struct iwl_trans *trans, - void *_tfd, u8 idx) -{ - if (trans->cfg->use_tfh) { - struct iwl_tfh_tfd *tfd = _tfd; - struct iwl_tfh_tb *tb = >tbs[idx]; - - return (dma_addr_t)(le64_to_cpu(tb->addr)); - } else { - struct iwl_tfd *tfd = _tfd; - struct iwl_tfd_tb *tb = >tbs[idx]; - dma_addr_t addr = get_unaligned_le32(>lo); - dma_addr_t hi_len; - - if (sizeof(dma_addr_t) <= sizeof(u32)) - return addr; - - hi_len = le16_to_cpu(tb->hi_n_len) & 0xF; - - /* -* shift by 16 twice to avoid warnings on 32-bit -* (where this code
[PATCH v2 23/26] iwlwifi: pcie: remove block and freeze operations from new transport
From: Sara SharonNew transport will be used only by op modes that supports buffer station offload - hence those will never be called. Clean it up. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 3 --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 22 +++--- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 16a057398de2..d39ca944f484 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2925,9 +2925,6 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .txq_alloc = iwl_trans_pcie_dyn_txq_alloc, .txq_free = iwl_trans_pcie_dyn_txq_free, - - .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, - .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index e8eb11282795..2019ccda31c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -107,9 +107,7 @@ static void iwl_pcie_gen2_txq_inc_wr_ptr(struct iwl_trans *trans, * if not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ - if (!txq->block) - iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (txq->id << 16)); + iwl_write32(trans, HBUS_TARG_WRPTR, txq->write_ptr | (txq->id << 16)); } static u8 iwl_pcie_gen2_get_num_tbs(struct iwl_trans *trans, @@ -341,19 +339,8 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, /* start timer if queue currently empty */ if (txq->read_ptr == txq->write_ptr) { - if (txq->wd_timeout) { - /* -* If the TXQ is active, then set the timer, if not, -* set the timer in remainder so that the timer will -* be armed with the right value when the station will -* wake up. -*/ - if (!txq->frozen) - mod_timer(>stuck_timer, - jiffies + txq->wd_timeout); - else - txq->frozen_expiry_remainder = txq->wd_timeout; - } + if (txq->wd_timeout) + mod_timer(>stuck_timer, jiffies + txq->wd_timeout); IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", txq->id); iwl_trans_ref(trans); } @@ -843,9 +830,6 @@ void iwl_trans_pcie_dyn_txq_free(struct iwl_trans *trans, int queue) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - trans_pcie->txq[queue].frozen_expiry_remainder = 0; - trans_pcie->txq[queue].frozen = false; - /* * Upon HW Rfkill - we stop the device, and then stop the queues * in the op_mode. Just for the sake of the simplicity of the op_mode, -- 2.11.0
[PATCH v2 10/26] iwlwifi: mvm: support new TX API
From: Sara SharonSupport the new TX command API for a000 devices. Command is a very slim version of current TX command. Generalize iwl_mvm_tx_mpdu to get rid of TX command dependencies. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 42 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c| 66 -- 2 files changed, 91 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h index 85744fa3bd4d..f83ee6e760d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -124,6 +125,20 @@ enum iwl_tx_flags { }; /* TX_FLAGS_BITS_API_S_VER_1 */ /** + * enum iwl_tx_cmd_flags - bitmasks for tx_flags in TX command for a000 + * @IWL_TX_FLAGS_CMD_RATE: use rate from the TX command + * @IWL_TX_FLAGS_ENCRYPT_DIS: frame should not be encrypted, even if it belongs + * to a secured STA + * @IWL_TX_FLAGS_HIGH_PRI: high priority frame (like EAPOL) - can affect rate + * selection, retry limits and BT kill + */ +enum iwl_tx_cmd_flags { + IWL_TX_FLAGS_CMD_RATE = BIT(0), + IWL_TX_FLAGS_ENCRYPT_DIS= BIT(1), + IWL_TX_FLAGS_HIGH_PRI = BIT(2), +}; /* TX_FLAGS_BITS_API_S_VER_3 */ + +/** * enum iwl_tx_pm_timeouts - pm timeout values in TX command * @PM_FRAME_NONE: no need to suspend sleep mode * @PM_FRAME_MGMT: fw suspend sleep mode for 100TU @@ -301,6 +316,31 @@ struct iwl_tx_cmd { struct ieee80211_hdr hdr[0]; } __packed; /* TX_CMD_API_S_VER_6 */ +struct iwl_dram_sec_info { + __le32 pn_low; + __le16 pn_high; + __le16 aux_info; +} __packed; /* DRAM_SEC_INFO_API_S_VER_1 */ + +/** + * struct iwl_tx_cmd_gen2 - TX command struct to FW for a000 devices + * ( TX_CMD = 0x1c ) + * @len: in bytes of the payload, see below for details + * @offload_assist: TX offload configuration + * @tx_flags: combination of _tx_cmd_flags + * @dram_info: FW internal DRAM storage + * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is + * cleared. Combination of RATE_MCS_* + */ +struct iwl_tx_cmd_gen2 { + __le16 len; + __le16 offload_assist; + __le32 flags; + struct iwl_dram_sec_info dram_info; + __le32 rate_n_flags; + struct ieee80211_hdr hdr[0]; +} __packed; /* TX_CMD_API_S_VER_7 */ + /* * TX response related data */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index d76cc422b040..279f56bf175f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -475,6 +475,39 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, memset(dev_cmd, 0, sizeof(*dev_cmd)); dev_cmd->hdr.cmd = TX_CMD; + + if (iwl_mvm_has_new_tx_api(mvm)) { + struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload; + u16 offload_assist = iwl_mvm_tx_csum(mvm, skb, hdr, info); + + /* padding is inserted later in transport */ + /* FIXME - check for AMSDU may need to be removed */ + if (ieee80211_hdrlen(hdr->frame_control) % 4 && + !(offload_assist & BIT(TX_CMD_OFFLD_AMSDU))) + offload_assist |= BIT(TX_CMD_OFFLD_PAD); + + cmd->offload_assist |= cpu_to_le16(offload_assist); + + /* Total # bytes to be transmitted */ + cmd->len = cpu_to_le16((u16)skb->len); + + /* Copy MAC header from skb into command buffer */ + memcpy(cmd->hdr, hdr, hdrlen); + + if (!info->control.hw_key) + cmd->flags |= cpu_to_le32(IWL_TX_FLAGS_ENCRYPT_DIS); + + /* For data packets rate info comes from the fw */ + if (ieee80211_is_data(hdr->frame_control) && sta) + goto out; + + cmd->flags |= cpu_to_le32(IWL_TX_FLAGS_CMD_RATE); + cmd->rate_n_flags = + cpu_to_le32(iwl_mvm_get_tx_rate(mvm, info, sta)); + + goto out; + } + tx_cmd = (struct iwl_tx_cmd
[PATCH v2 15/26] iwlwifi: mvm: remove unnecessary debugging from UMAC scan
From: Luca CoelhoThere are several occasions where a scan of the same type is requested concurrently, so logging every time this happens is just noisy and unnecessary. Remove the logging for these cases. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 5 + 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index ce6a2b3b021e..9668f945b4e6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1037,11 +1037,8 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) return -ENOBUFS; - if (type == mvm->scan_type) { - IWL_DEBUG_SCAN(mvm, - "Ignoring UMAC scan config of the same type\n"); + if (type == mvm->scan_type) return 0; - } if (iwl_mvm_has_new_tx_api(mvm)) cmd_size = sizeof(struct iwl_scan_config); -- 2.11.0
[PATCH v2 08/26] iwlwifi: mvm: spin off SAR profile selection function
From: Luca CoelhoFor dynamic SAR, we will need to select the current profile from different places. In preparation for that, spin the profile selection code out of iwl_mvm_sar_init(). Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 4 ++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 73 +++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d74ae15b2d85..119a3bd92c50 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2116,6 +2116,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) */ iwl_mvm_update_changed_regdom(mvm); + if (!unified_image) + /* Re-configure default SAR profile */ + iwl_mvm_sar_select_profile(mvm, 1, 1); + if (mvm->net_detect) { /* If this is a non-unified image, we restart the FW, * so no need to stop the netdetect scan. If that diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 1679104e19e9..6360361c576d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1123,49 +1123,78 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) return ret; } -static int iwl_mvm_sar_init(struct iwl_mvm *mvm) +int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { struct iwl_dev_tx_power_cmd cmd = { .v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), }; - int ret, i, j, idx; + int i, j, idx; + int profs[IWL_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; int len = sizeof(cmd); + BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS < 2); + BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS * IWL_NUM_SUB_BANDS != +IWL_MVM_SAR_TABLE_SIZE); + if (!fw_has_capa(>fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) len = sizeof(cmd.v3); - ret = iwl_mvm_sar_get_wrds_table(mvm); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* we don't fail if the table is not available */ - return 0; - } + for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { + struct iwl_mvm_sar_profile *prof; - /* if profile 0 is disabled, there's nothing else to do here */ - if (!mvm->sar_profiles[0].enabled) - return 0; + /* don't allow SAR to be disabled (profile 0 means disable) */ + if (profs[i] == 0) + return -EPERM; - IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); + /* we are off by one, so allow up to IWL_MVM_SAR_PROFILE_NUM */ + if (profs[i] > IWL_MVM_SAR_PROFILE_NUM) + return -EINVAL; - BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS * IWL_NUM_SUB_BANDS != -IWL_MVM_SAR_TABLE_SIZE); + /* profiles go from 1 to 4, so decrement to access the array */ + prof = >sar_profiles[profs[i] - 1]; + + /* if the profile is disabled, do nothing */ + if (!prof->enabled) { + IWL_DEBUG_RADIO(mvm, "SAR profile %d is disabled.\n", + profs[i]); + /* if one of the profiles is disabled, we fail all */ + return -ENOENT; + } - for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i); for (j = 0; j < IWL_NUM_SUB_BANDS; j++) { idx = (i * IWL_NUM_SUB_BANDS) + j; cmd.v3.per_chain_restriction[i][j] = - cpu_to_le16(mvm->sar_profiles[0].table[idx]); + cpu_to_le16(prof->table[idx]); IWL_DEBUG_RADIO(mvm, "Band[%d] = %d * .125dBm\n", - j, mvm->sar_profiles[0].table[idx]); + j, prof->table[idx]); } } - ret = iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, ); - if (ret) - IWL_ERR(mvm, "failed to set per-chain TX power: %d\n", ret); + IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); + + return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, ); +} + +static int iwl_mvm_sar_init(struct iwl_mvm *mvm) +{ + int ret; + + ret = iwl_mvm_sar_get_wrds_table(mvm); + if (ret < 0) { +
[PATCH v2 09/26] iwlwifi: mvm: add support for EWRD (Dynamic SAR) ACPI table
From: Luca CoelhoDynamic SAR allows changing TX power limits at runtime to comply with SAR regulations on multiple form factors (e.g. tablet vs. clamshell mode). To support this, a new table was added to ACPI, which is called Extended Wireless Regulatory Descriptor (EWRD). This table allows OEMs to define different TX power profiles for each form-factor or usage mode. Read this new table and store it in our SAR profiles table, in preparation for Dynamic SAR support. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 114 +++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 11 ++- 2 files changed, 108 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 6360361c576d..2a4c952ef01a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -992,8 +992,11 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) #ifdef CONFIG_ACPI #define ACPI_WRDS_METHOD "WRDS" -#define ACPI_WRDS_WIFI (0x07) +#define ACPI_EWRD_METHOD "EWRD" +#define ACPI_WIFI_DOMAIN (0x07) #define ACPI_WRDS_WIFI_DATA_SIZE (IWL_MVM_SAR_TABLE_SIZE + 2) +#define ACPI_EWRD_WIFI_DATA_SIZE ((IWL_MVM_SAR_PROFILE_NUM - 1) * \ +IWL_MVM_SAR_TABLE_SIZE + 3) static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm, union acpi_object *table, @@ -1051,7 +1054,7 @@ static union acpi_object *iwl_mvm_sar_find_wifi_pkg(struct iwl_mvm *mvm, domain = _pkg->package.elements[0]; if (domain->type == ACPI_TYPE_INTEGER && - domain->integer.value == ACPI_WRDS_WIFI) + domain->integer.value == ACPI_WIFI_DOMAIN) break; wifi_pkg = NULL; @@ -1123,6 +1126,78 @@ static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) return ret; } +static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) +{ + union acpi_object *wifi_pkg; + acpi_handle root_handle; + acpi_handle handle; + struct acpi_buffer ewrd = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + bool enabled; + int i, n_profiles, ret; + + root_handle = ACPI_HANDLE(mvm->dev); + if (!root_handle) { + IWL_DEBUG_RADIO(mvm, + "Could not retrieve root port ACPI handle\n"); + return -ENOENT; + } + + /* Get the method's handle */ + status = acpi_get_handle(root_handle, (acpi_string)ACPI_EWRD_METHOD, +); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_RADIO(mvm, "EWRD method not found\n"); + return -ENOENT; + } + + /* Call EWRD with no arguments */ + status = acpi_evaluate_object(handle, NULL, NULL, ); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_RADIO(mvm, "EWRD invocation failed (0x%x)\n", status); + return -ENOENT; + } + + wifi_pkg = iwl_mvm_sar_find_wifi_pkg(mvm, ewrd.pointer, +ACPI_EWRD_WIFI_DATA_SIZE); + if (IS_ERR(wifi_pkg)) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if ((wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) || + (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER)) { + ret = -EINVAL; + goto out_free; + } + + enabled = !!(wifi_pkg->package.elements[1].integer.value); + n_profiles = wifi_pkg->package.elements[2].integer.value; + + for (i = 0; i < n_profiles; i++) { + /* the tables start at element 3 */ + static int pos = 3; + + /* The EWRD profiles officially go from 2 to 4, but we +* save them in sar_profiles[1-3] (because we don't +* have profile 0). So in the array we start from 1. +*/ + ret = iwl_mvm_sar_set_profile(mvm, + _pkg->package.elements[pos], + >sar_profiles[i + 1], + enabled); + if (ret < 0) + break; + + /* go to the next table */ + pos += IWL_MVM_SAR_TABLE_SIZE; + } + +out_free: + kfree(ewrd.pointer); + return ret; +} + int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { struct iwl_dev_tx_power_cmd cmd = { @@ -1176,6 +1251,18 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, ); } +#else /* CONFIG_ACPI */
[PATCH v2 04/26] iwlwifi: mvm: prepare for station count change
From: Sara SharonIn a000 devices we will support up to 32 stations. The max station define is used also for invalid station marking which makes finding usages of actual maximum station pretty hard to sort through - change it to be a different define in order to make future changes easier. Use also ARRAY_SIZE intead of define when possible. Do not move yet to 32 stations until firmware do it though. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c| 2 +- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/fw-api-mac.h| 4 ++- drivers/net/wireless/intel/iwlwifi/mvm/fw.c| 6 ++--- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 6 ++--- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 16 ++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 12 - drivers/net/wireless/intel/iwlwifi/mvm/rx.c| 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sf.c| 6 ++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 30 +++--- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 22 drivers/net/wireless/intel/iwlwifi/mvm/tof.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tt.c| 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c| 6 ++--- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 +- 18 files changed, 66 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 5bdb6c2c8390..49b4418e6c35 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -756,7 +756,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * Rssi update while not associated - can happen since the statistics * are handled asynchronously */ - if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) + if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA) return; /* No BT - reports should be disabled */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d65acfa3b89b..d74ae15b2d85 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1208,7 +1208,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) { + if (mvmvif->ap_sta_id == IWL_MVM_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) { ret = 1; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index f4d75ffe3d8a..5d475b4850ae 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -280,7 +280,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, mvmvif->queue_params[i].uapsd); if (vif->type == NL80211_IFTYPE_STATION && - ap_sta_id != IWL_MVM_STATION_COUNT) { + ap_sta_id != IWL_MVM_INVALID_STA) { struct iwl_mvm_sta *mvm_sta; mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index a260cd503200..7b33ff398332 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -330,7 +330,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, mutex_lock(>mutex); - for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { + for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i); sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], lockdep_is_held(>mutex)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h index 480a54af4534..d3cdd889c85c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h @@ -73,7 +73,9 @@ #define NUM_MAC_INDEX (NUM_MAC_INDEX_DRIVER + 1) #define NUM_MAC_INDEX_CDB (NUM_MAC_INDEX_DRIVER + 2) -#define IWL_MVM_STATION_COUNT 16 +#define IWL_MVM_STATION_COUNT 16 +#define IWL_MVM_INVALID_STA
[PATCH v2 06/26] iwlwifi: mvm: disable multi-queue for a000 devices
From: Sara SharonFirmware isn't configuring multi RX queue hardware yet in the self init mode. Disable it for now until we have an API that enables it. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 61cafb541554..4c5088643b2b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1240,7 +1240,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) } /* Init RSS configuration */ - if (iwl_mvm_has_new_rx_api(mvm)) { + /* TODO - remove a000 disablement when we have RXQ config API */ + if (iwl_mvm_has_new_rx_api(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { ret = iwl_send_rss_cfg_cmd(mvm); if (ret) { IWL_ERR(mvm, "Failed to configure RSS queues: %d\n", -- 2.11.0
[PATCH v2 03/26] iwlwifi: cleanup unused function
From: Sara Sharoniwl_has_secure_boot() isn't getting called anywhere. Clean it up. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 10 -- 1 file changed, 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 717e089ff036..06034a71a190 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -90,16 +90,6 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_8000, }; -static inline bool iwl_has_secure_boot(u32 hw_rev, - enum iwl_device_family family) -{ - /* return 1 only for family 8000 B0 */ - if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC)) - return true; - - return false; -} - /* * LED mode *IWL_LED_DEFAULT: use device default -- 2.11.0
[PATCH v2 07/26] iwlwifi: mvm: refactor SAR init to prepare for dynamic SAR
From: Haim DreyfussWe are adding support for dynamic TX power tables for SAR (specific absorption rate) compliance. Currently, we only support a single (static) TX power table, which is read from ACPI, and use it statically. To prepare for more tables that can be switched dynamically, refactor the SAR init flow to allow reusage and add the current static table as a single entry in an array of tables. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 155 --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 17 ++- 2 files changed, 107 insertions(+), 65 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 4c5088643b2b..1679104e19e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -990,85 +990,87 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) sizeof(cmd), ); } -#define ACPI_WRDS_METHOD "WRDS" -#define ACPI_WRDS_WIFI (0x07) -#define ACPI_WRDS_TABLE_SIZE 10 +#ifdef CONFIG_ACPI +#define ACPI_WRDS_METHOD "WRDS" +#define ACPI_WRDS_WIFI (0x07) +#define ACPI_WRDS_WIFI_DATA_SIZE (IWL_MVM_SAR_TABLE_SIZE + 2) + +static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm, + union acpi_object *table, + struct iwl_mvm_sar_profile *profile, + bool enabled) +{ + int i; -struct iwl_mvm_sar_table { - bool enabled; - u8 values[ACPI_WRDS_TABLE_SIZE]; -}; + profile->enabled = enabled; -#ifdef CONFIG_ACPI -static int iwl_mvm_sar_get_wrds(struct iwl_mvm *mvm, union acpi_object *wrds, - struct iwl_mvm_sar_table *sar_table) + for (i = 0; i < IWL_MVM_SAR_TABLE_SIZE; i++) { + if ((table[i].type != ACPI_TYPE_INTEGER) || + (table[i].integer.value > U8_MAX)) + return -EINVAL; + + profile->table[i] = table[i].integer.value; + } + + return 0; +} + +static union acpi_object *iwl_mvm_sar_find_wifi_pkg(struct iwl_mvm *mvm, + union acpi_object *data, + int data_size) { - union acpi_object *data_pkg; - u32 i; + int i; + union acpi_object *wifi_pkg; - /* We need at least two packages, one for the revision and one + /* +* We need at least two packages, one for the revision and one * for the data itself. Also check that the revision is valid * (i.e. it is an integer set to 0). - */ - if (wrds->type != ACPI_TYPE_PACKAGE || - wrds->package.count < 2 || - wrds->package.elements[0].type != ACPI_TYPE_INTEGER || - wrds->package.elements[0].integer.value != 0) { - IWL_DEBUG_RADIO(mvm, "Unsupported wrds structure\n"); - return -EINVAL; +*/ + if (data->type != ACPI_TYPE_PACKAGE || + data->package.count < 2 || + data->package.elements[0].type != ACPI_TYPE_INTEGER || + data->package.elements[0].integer.value != 0) { + IWL_DEBUG_RADIO(mvm, "Unsupported packages structure\n"); + return ERR_PTR(-EINVAL); } /* loop through all the packages to find the one for WiFi */ - for (i = 1; i < wrds->package.count; i++) { + for (i = 1; i < data->package.count; i++) { union acpi_object *domain; - data_pkg = >package.elements[i]; + wifi_pkg = >package.elements[i]; /* Skip anything that is not a package with the right * amount of elements (i.e. domain_type, -* enabled/disabled plus the sar table size. +* enabled/disabled plus the actual data size. */ - if (data_pkg->type != ACPI_TYPE_PACKAGE || - data_pkg->package.count != ACPI_WRDS_TABLE_SIZE + 2) + if (wifi_pkg->type != ACPI_TYPE_PACKAGE || + wifi_pkg->package.count != data_size) continue; - domain = _pkg->package.elements[0]; + domain = _pkg->package.elements[0]; if (domain->type == ACPI_TYPE_INTEGER && domain->integer.value == ACPI_WRDS_WIFI) break; - data_pkg = NULL; + wifi_pkg = NULL; } - if (!data_pkg) - return -ENOENT; - - if (data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) - return -EINVAL; - - sar_table->enabled = !!(data_pkg->package.elements[1].integer.value); -
[PATCH v2 00/26] iwlwifi: updates intended for v4.12 2017-04-13
From: Luca CoelhoHi, This is v2 of the second patch set intended for v4.12. These are the changes: * A large amount of work on the A000 device series; * A couple of cleanup patches; * Dynamic SAR support; As usual, I'm pushing this to a pending branch, for kbuild bot, and will send a pull-request later. In v2, I fixed SAR compilation when CONFIG_ACPI is not set (thanks to kbuildbot) and also squashed some other SAR fixes. Please review. Cheers, Luca. Emmanuel Grumbach (1): iwlwifi: mvm: tell the firmware about the U-APSD parameters Goodstein, Mordechay (1): iwlwifi: mvm: move new API code to the end Haim Dreyfuss (1): iwlwifi: mvm: refactor SAR init to prepare for dynamic SAR Luca Coelho (3): iwlwifi: mvm: spin off SAR profile selection function iwlwifi: mvm: add support for EWRD (Dynamic SAR) ACPI table iwlwifi: mvm: remove unnecessary debugging from UMAC scan Sara Sharon (20): iwlwifi: mvm: read new secure boot registers iwlwifi: mvm: add queues after adding station iwlwifi: cleanup unused function iwlwifi: mvm: prepare for station count change iwlwifi: mvm: use same scan API for all a000 devices iwlwifi: mvm: disable multi-queue for a000 devices iwlwifi: mvm: support new TX API iwlwifi: pcie: introduce a000 TX queues management iwlwifi: mvm: support a000 SCD queue configuration iwlwifi: mvm: support moving to mgmt tid iwlwifi: pcie: copy TX functions to new transport iwlwifi: pcie: cleanup old transport code from gen2 iwlwifi: pcie: support new TX command iwlwifi: pcie: rewrite TFD creation iwlwifi: pcie: support host commands in new transport iwlwifi: pcie: support new write pointer width iwlwifi: pcie: remove block and freeze operations from new transport iwlwifi: pcie: prepare for dynamic queue allocation iwlwifi: pcie: introduce new stop_device iwlwifi: pcie: alloc queues dynamically drivers/net/wireless/intel/iwlwifi/Makefile| 2 +- drivers/net/wireless/intel/iwlwifi/iwl-config.h| 10 - drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 2 + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 71 +- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c| 6 +- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/fw-api-mac.h| 4 +- .../net/wireless/intel/iwlwifi/mvm/fw-api-scan.h | 14 +- .../net/wireless/intel/iwlwifi/mvm/fw-api-sta.h| 16 +- drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h | 42 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c| 318 +-- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 16 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 27 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 12 +- drivers/net/wireless/intel/iwlwifi/mvm/rx.c| 71 +- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 85 +- drivers/net/wireless/intel/iwlwifi/mvm/sf.c| 6 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 192 ++-- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 22 +- drivers/net/wireless/intel/iwlwifi/mvm/tof.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tt.c| 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c| 84 +- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 45 +- .../net/wireless/intel/iwlwifi/pcie/ctxt-info.c| 2 +- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 42 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 9 +- .../net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 147 +++ drivers/net/wireless/intel/iwlwifi/pcie/trans.c| 48 +- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 996 + drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 207 ++--- 34 files changed, 2026 insertions(+), 488 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c -- 2.11.0
[PATCH v2 01/26] iwlwifi: mvm: read new secure boot registers
From: Sara SharonAddresses were changed for a000 devices. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 13 ++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index bb7e0d642981..e1aa1f7836fc 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -400,6 +400,8 @@ enum aux_misc_master1_en { #define PREG_AUX_BUS_WPROT_0 0xA04CC0 #define SB_CPU_1_STATUS0xA01E30 #define SB_CPU_2_STATUS0xA01E34 +#define UMAG_SB_CPU_1_STATUS 0xA038C0 +#define UMAG_SB_CPU_2_STATUS 0xA038C4 /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index e481bb050c6e..6adbd4bcb40a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -639,11 +639,18 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, ret = iwl_wait_notification(>notif_wait, _wait, MVM_UCODE_ALIVE_TIMEOUT); if (ret) { - if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + struct iwl_trans *trans = mvm->trans; + + if (trans->cfg->gen2) + IWL_ERR(mvm, + "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", + iwl_read_prph(trans, UMAG_SB_CPU_1_STATUS), + iwl_read_prph(trans, UMAG_SB_CPU_2_STATUS)); + else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", - iwl_read_prph(mvm->trans, SB_CPU_1_STATUS), - iwl_read_prph(mvm->trans, SB_CPU_2_STATUS)); + iwl_read_prph(trans, SB_CPU_1_STATUS), + iwl_read_prph(trans, SB_CPU_2_STATUS)); mvm->cur_ucode = old_type; return ret; } -- 2.11.0
[PATCH v2 02/26] iwlwifi: mvm: add queues after adding station
From: Sara SharonCurrently aux & broadcast queues are added before calling add station, which results with a SCD_QUEUE_CFG command sent with a station id unknown yet to fw. While this works for pre-a000 firmware, the a000 fw requires the order to be reversed. The reason the change is only for a000 devices and not for previous devices is that we cannot reverse the order since the tfd_queue_mask containing the aux queue will cause FW to assert on adding a queue mask with a queue that is not enabled. This is not a problem in a000 fw since the tfd_queue_mask was removed from the add sta API. Signed-off-by: Sara Sharon Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 90 ++-- 1 file changed, 58 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 2d68cee41306..7d6a5dbb50ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1700,25 +1700,11 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, return ret; } -int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) +static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm) { unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? mvm->cfg->base_params->wd_timeout : IWL_WATCHDOG_DISABLED; - int ret; - - lockdep_assert_held(>mutex); - - /* Map Aux queue to fifo - needs to happen before adding Aux station */ - if (!iwl_mvm_is_dqa_supported(mvm)) - iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue, - IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout); - - /* Allocate aux station and assign to it the aux queue */ - ret = iwl_mvm_allocate_int_sta(mvm, >aux_sta, BIT(mvm->aux_queue), - NL80211_IFTYPE_UNSPECIFIED); - if (ret) - return ret; if (iwl_mvm_is_dqa_supported(mvm)) { struct iwl_trans_txq_scd_cfg cfg = { @@ -1731,14 +1717,43 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) iwl_mvm_enable_txq(mvm, mvm->aux_queue, mvm->aux_queue, 0, , wdg_timeout); + } else { + iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue, + IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout); } +} - ret = iwl_mvm_add_int_sta_common(mvm, >aux_sta, NULL, -MAC_INDEX_AUX, 0); +int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) +{ + int ret; + + lockdep_assert_held(>mutex); + /* Allocate aux station and assign to it the aux queue */ + ret = iwl_mvm_allocate_int_sta(mvm, >aux_sta, BIT(mvm->aux_queue), + NL80211_IFTYPE_UNSPECIFIED); if (ret) + return ret; + + /* Map Aux queue to fifo - needs to happen before adding Aux station */ + if (!iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_enable_aux_queue(mvm); + + ret = iwl_mvm_add_int_sta_common(mvm, >aux_sta, NULL, +MAC_INDEX_AUX, 0); + if (ret) { iwl_mvm_dealloc_int_sta(mvm, >aux_sta); - return ret; + return ret; + } + + /* +* For a000 firmware and on we cannot add queue to a station unknown +* to firmware so enable queue here - after the station was added +*/ + if (iwl_mvm_has_new_tx_api(mvm)) + iwl_mvm_enable_aux_queue(mvm); + + return 0; } int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) @@ -1789,22 +1804,21 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_int_sta *bsta = >bcast_sta; static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; const u8 *baddr = _baddr; + int queue = 0; int ret; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, vif, false, false); + struct iwl_trans_txq_scd_cfg cfg = { + .fifo = IWL_MVM_TX_FIFO_VO, + .sta_id = mvmvif->bcast_sta.sta_id, + .tid = IWL_MAX_TID_COUNT, + .aggregate = false, + .frame_limit = IWL_FRAME_LIMIT, + }; lockdep_assert_held(>mutex); if (iwl_mvm_is_dqa_supported(mvm)) { - struct iwl_trans_txq_scd_cfg cfg = { - .fifo = IWL_MVM_TX_FIFO_VO, - .sta_id = mvmvif->bcast_sta.sta_id, - .tid = IWL_MAX_TID_COUNT, - .aggregate = false, - .frame_limit = IWL_FRAME_LIMIT, - }; -
Email change
Hi everyone, I'm parting ways with Tieto today so my email is going to become defunct. I'll be reachable via: kazikcz at gmail dot com. Michał